在Entity Framework中使用存儲過程(五):如何通過存儲過程維護多對多關係?
對於數據庫設計來說,多對多(或者一對多)是一種常見的數據關係,比如聯係人和地址之間的關係。我們通常采用建立關係表的方式來表示這種關係,比如我們創建一張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: <AssociationSetMapping Name="Contact_Address" TypeName="ContactModel.Contact_Address" StoreEntitySet="Contact_Address">
2: <EndProperty Name="Address">
3: <ScalarProperty Name="AddressID" ColumnName="AddressID" />
4: </EndProperty>
5: <EndProperty Name="Contact">
6: <ScalarProperty Name="ContactID" ColumnName="ContactID" />
7: </EndProperty>
8: </AssociationSetMapping>
然後,在AssociationSetMapping節點中添加ModificationFunctionMapping節點,在InsertFunction和DeleteFunction中分別定義我們創建的兩個存儲過程的映射關係。這個AssociationSetMapping節點如下所示,FunctionName中的命名空間根據你具體的定義作相應修改。
1: <AssociationSetMapping Name="Contact_Address" TypeName="ContactModel.Contact_Address" StoreEntitySet="Contact_Address">
2: <EndProperty Name="Address">
3: <ScalarProperty Name="AddressID" ColumnName="AddressID" />
4: </EndProperty>
5: <EndProperty Name="Contact">
6: <ScalarProperty Name="ContactID" ColumnName="ContactID" />
7: </EndProperty>
8: <ModificationFunctionMapping>
9: <InsertFunction FunctionName="ContactModel.Store.AddAddress">
10: <EndProperty Name="Address">
11: <ScalarProperty Name="AddressID" ParameterName="AddressID"/>
12: </EndProperty>
13: <EndProperty Name="Contact">
14: <ScalarProperty Name="ContactID" ParameterName="ContactID"/>
15: </EndProperty>
16: </InsertFunction>
17: <DeleteFunction FunctionName="ContactModel.Store.DeleteAddress">
18: <EndProperty Name="Address">
19: <ScalarProperty Name="AddressID" ParameterName="AddressID"/>
20: </EndProperty>
21: <EndProperty Name="Contact">
22: <ScalarProperty Name="ContactID" ParameterName="ContactID"/>
23: </EndProperty>
24: </DeleteFunction>
25: </ModificationFunctionMapping>
26: </AssociationSetMapping>
步驟五、編寫建立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這張表的數據,你會發現相應的關係已經被正確地保存。
在Entity Framework中使用存儲過程(一):實現存儲過程的自動映射
在Entity Framework中使用存儲過程(二):具有繼承關係實體的存儲過程如何定義?
在Entity Framework中使用存儲過程(三):邏輯刪除的實現與自增長列值返回
在Entity Framework中使用存儲過程(四):如何為Delete存儲過程參數賦上Current值?
在Entity Framework中使用存儲過程(五):如何通過存儲過程維護多對多關係?
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁麵明顯位置給出原文連接,否則保留追究法律責任的權利。
最後更新:2017-10-27 11:34:25