博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
在Entity Framework中使用存储过程(五):如何通过存储过程维护多对多关系?
阅读量:7220 次
发布时间:2019-06-29

本文共 4033 字,大约阅读时间需要 13 分钟。

对于数据库设计来说,多对多(或者一对多)是一种常见的数据关系,比如联系人和地址之间的关系。我们通常采用建立关系表的方式来表示这种关系,比如我们创建一张Contact—_Address(ContactID, AddressID)来存储联系人和地址之间的关系。如果我们最终需要通过存储过程的方式来维护他们之间的关系,该如何做呢?本篇文章给你一个具体的例子来演示如果采用存储过程来建立和删除实体之间的关系。

目录

步骤一、创建数据表

步骤二、创建建立/解除关系的存储过程
步骤三、创建实体数据模型
步骤四、建立关系与存储过程的映射
步骤五、编写建立Contact/Address关联的程序

 步骤一、创建数据表

我们就采用上面提到过的联系人/地址关联的场景,现在我们通过下面的SQL来创建三张表。Contact和Address分别用于存储联系人和地址记录,两者之间的关系存储在Contact_Address表中。

Address:

1: CREATE TABLE [Address]
2: (
3:     [AddressID]     [INT]          PRIMARY KEY,
4:     [StreetAddress] [NVARCHAR](50) NOT NULL,
5:     [City]          [NVARCHAR](50) NOT NULL
6: )

Contact:

1: CREATE TABLE [Contact]
2: (
3:     [ContactID]        [INT]            PRIMARY KEY,
4:     [LastName]        [NVARCHAR](50)    NOT NULL,
5:     [FirstName]        [NVARCHAR](50)    NOT NULL
6: )

Contact_Address:

1: CREATE TABLE [Contact_Address]
2: (
3:     [ContactID] [INT]  NOT NULL REFERENCES [Contact]([ContactID]),
4:     [AddressID] [INT]  NOT NULL REFERENCES [Address]([AddressID]),
5:     PRIMARY KEY([ContactID],[AddressID])
6: )

上面创建的三张数据表在数据库中具有如下图所示的关系:

步骤二、创建建立/解除关系的存储过程

我们需要演示的是如何通过存储过程来建立和接触Contact和Address之间的关系,也就是通过存储过程来维护Contact_Address这张表的记录。我们只需创建两个对应的存储过程:AddAddress和DeleteAddress。和基于实体数据更新同时需要CUD三个存储过程不同,这里只需CD两个存储过程。

AddAddress:

1: CREATE PROCEDURE [AddAddress]
2: ( @ContactID [INT],
3:   @AddressID [INT]
4: )
5: AS
6: BEGIN
7:     INSERT Contact_Address(ContactID, AddressID)
8:     VALUES(@ContactID, @AddressID);
9: END

DeleteAddress:

1: CREATE PROCEDURE [DeleteAddress]
2:     @ContactID int,
3:     @AddressID int
4: AS
5: 
6: BEGIN
7:     DELETE Contact_Address
8:     WHERE ContactID = @ContactID
9:       AND AddressID = @AddressID
10: END

步骤三、创建实体数据模型

然后我们只需要按照VS提供的实体数据模型创建向导,通过选择上面创建的三张表和两个存储过程建立如下一个.edmx模型。我们可以看到,虽然我们选择了三张表,EF能够解析出Contact_Address为关系表,所以最终生成出来的就是我们希望的具有多对多(如果一个联系人只有一个地址,你可以将关系更新成一对多)。需要注意的是,只有当关系表仅仅包括外键的情况下才会被EF认为是关系表。如果Contact_Address具有额外的字段,在建立模型的时候仍然被认作是实体表。

步骤四、建立关系与存储过程的映射

由于在建立模型的时候我们仅仅是选择了我们创建的两个存储过程,所以对于.edmx模型的元数据(概念模型、存储模型和C/S映射)来说,这两个存储过程仅仅体现在存储模型中。现在我们需要最终调用它们来建立或者删除Contact和Address之间的关系,我们肯定需要在C/S映射中定义实体关系(概念模型)和这两个存储过程对应的Function(存储模型)之间的关联。

你肯定知道我们可以通过EF提供的设计器为每一个实体类型定义CUD存储过程,以及实体属性和存储过程参数之间的映射关系。但是现在我们要完成的却实关系(Association)与存储过程之间的映射。很遗憾,这项工作没有得到EF设计器可视化的支持,我们不得不通过手工修改.edmx模型的XML来完成。

现在你需要通过XML Editor打开.edmx文件,定位到C/S映射节点(<edmx:Mappings>),找到如下一段表示Contact/Address关系映射的名称为AssociationSetMapping的XML元素。

1: 
2:   
3:     
4:   
5:   
6:     
7:   
8: 

然后,在AssociationSetMapping节点中添加ModificationFunctionMapping节点,在InsertFunction和DeleteFunction中分别定义我们创建的两个存储过程的映射关系。这个AssociationSetMapping节点如下所示,FunctionName中的命名空间根据你具体的定义作相应修改。

1: 
2:   
3:     
4:   
5:   
6:     
7:   
8:   
9:     
10:       
11:         
12:       
13:       
14:         
15:       
16:     
17:     
18:       
19:         
20:       
21:       
22:         
23:       
24:     
25:   
26: 

步骤五、编写建立Contact/Address关联的程序

现在我们编写如下的程序,先后创建2个地址和3个联系人,并分别建立它们之间的关系后,通过调用ObjectContext的SaveChanges方法提交到数据库中。

1: Address address1    = Address.CreateAddress(1, "Jinji Hu Rd #328 E101", "Su Zhou");
2: Address address2    = Address.CreateAddress(2, "XingHu Street #328 Blk 11", "Su Zhou");
3: Contact zhangSan    = Contact.CreateContact(1, "Zhang", "San");
4: Contact liSi        = Contact.CreateContact(2, "Li", "Si");
5: Contact wangWu      = Contact.CreateContact(3, "Wang", "Wu");
6: 
7: zhangSan.Addresses.Add(address1);
8: liSi.Addresses.Add(address1);
9: wangWu.Addresses.Add(address2);
10: 
11: using (ContactInformationEntities context = new ContactInformationEntities())
12: {
13:     context.Contacts.AddObject(zhangSan);
14:     context.Contacts.AddObject(liSi);
15:     context.Contacts.AddObject(wangWu);
16:     context.SaveChanges();
17: }

查看Contact_Address这张表的数据,你会发现相应的关系已经被正确地保存。

作者:蒋金楠
微信公众账号:大内老A
微博:
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号
蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
你可能感兴趣的文章
Nikto是一款Web安全扫描工具,可以扫描指定主机的web类型,主机名,特定目录,cookie,特定CGI漏洞,XSS漏洞,SQL注入漏洞等,非常强大滴说。。。...
查看>>
[Google Guava]学习--新集合类型Multimap
查看>>
转:Java NIO系列教程(二) Channel
查看>>
线程相关参数
查看>>
Android提升篇系列:Android项目代码优化实践
查看>>
改造 Android 官方架构组件 ViewModel
查看>>
2400万AI自拍再进阶,荣耀10青春版发布开启新自拍时代
查看>>
贾跃亭被指拿恒大的投资款告投资人 总费用超2000万
查看>>
春运守护者 大陆首批台湾籍乘务长黄佳莹
查看>>
潮汕明代皇封御葬古墓受损追踪:当地相关部门介入
查看>>
“老票证”述时代变迁:从凭“票”买到“任意”购
查看>>
做java该要了解的东西
查看>>
春节出行带个对讲机 旅行实测威诺VR-N65
查看>>
河北旅游发展蓝皮书:借力雄安打造京津冀世界旅游品牌
查看>>
江西一名男婴被弃医院9个月 其父自首其母接回孩子
查看>>
江西去年为企业、居民减税659亿元 发行1082亿元政府债券
查看>>
GitHub发布Python安全警告 识别依赖包的安全漏洞
查看>>
讲好文创的时代故事
查看>>
支持53种语言预训练模型,斯坦福发布全新NLP工具包StanfordNLP
查看>>
翟欣欣微博发声解释“真相”
查看>>