自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

LINQ to SQL多對(duì)多表間關(guān)系的維護(hù)方法

開(kāi)發(fā) 后端
我們經(jīng)常會(huì)碰到維護(hù)多對(duì)多(many to many)關(guān)系表間關(guān)系的操作,本文將介紹的是相關(guān)的維護(hù)方法。

在項(xiàng)目開(kāi)發(fā)中,經(jīng)常會(huì)碰到維護(hù)多對(duì)多(many to many)關(guān)系表間關(guān)系的操作,例如為人員配置角色、為人員配置部門、為產(chǎn)品配置類別等。如果沒(méi)有經(jīng)過(guò)程序設(shè)計(jì)而直接進(jìn)行開(kāi)發(fā),將會(huì)過(guò)多地關(guān)注其細(xì)節(jié)問(wèn)題,如:應(yīng)刪除那些數(shù)據(jù)、應(yīng)添加哪些數(shù)據(jù)、應(yīng)保留哪些數(shù)據(jù)等,導(dǎo)致開(kāi)發(fā)效率降低。

名詞解釋

在本文開(kāi)始之前,首先以用戶-用戶角色-角色表為例,聲明三個(gè)概念:

clip_image004

l  主表:如果為用戶配置角色,那么用戶就是主表;如果為角色配置用戶,那么角色就是主表。

l  從表:如果為用戶配置角色,那么角色就是從表。

l  關(guān)系表:記錄用戶與角色表間關(guān)系的表。

行為描述

經(jīng)過(guò)總結(jié),發(fā)現(xiàn)其行為有統(tǒng)一的地方:傳遞主表對(duì)象與從表對(duì)象集合->獲取現(xiàn)有關(guān)系->對(duì)比出要?jiǎng)h除的關(guān)系->對(duì)比出要添加的關(guān)系->提交更改。

在下面的文章中,將一步步介紹完成的過(guò)程。

測(cè)試用例

使用ASP.NET網(wǎng)站程序,新建如下圖所示的頁(yè)面:

clip_image006

在左側(cè)的用戶選擇DropDownList中,選擇一個(gè)現(xiàn)有用戶后,會(huì)在右側(cè)的CheckBoxList中顯示其具有的角色。在進(jìn)行完配置后,可以點(diǎn)擊上方的”保存”LinkButton進(jìn)行保存。

下面我將4以種情況,來(lái)展示這個(gè)示例。在每個(gè)操作完成后,我們執(zhí)行以下腳本,來(lái)查看操作是否成功:

腳本:

  1. SELECT * FROM [dbo].[UsersInRoles] 

開(kāi)始測(cè)試前:

clip_image008

添加一個(gè)關(guān)系

在本次操作中,將為馬六配置一個(gè)“Java程序員”的角色。

clip_image010

點(diǎn)擊保存后,查看數(shù)據(jù)庫(kù)數(shù)據(jù):

clip_image012

可以看到,已經(jīng)成功添加一個(gè)關(guān)系。

添加兩個(gè)關(guān)系,其中一個(gè)將新建,一個(gè)不做處理

在本次操作中,將為馬六配置 “Java程序員 + .NET程序員”的角色。

clip_image014

點(diǎn)擊保存后,查看數(shù)據(jù)庫(kù)數(shù)據(jù):

clip_image016

可以看到數(shù)據(jù)庫(kù)中的關(guān)系數(shù)據(jù)變?yōu)榱藘蓷l,并且RoleID為“63B04…”的關(guān)系數(shù)據(jù)的主鍵“064AB…”并沒(méi)有發(fā)生改變,這說(shuō)明我并沒(méi)有做“全部刪除,再全部添加”的暴力型操作。

添加兩個(gè)關(guān)系,其中一個(gè)將新建,一個(gè)不做處理,一個(gè)將刪除

在本次操作中,將為馬六配置 “Java程序員 + 項(xiàng)目經(jīng)理”的角色。

clip_image018

點(diǎn)擊保存后,查看數(shù)據(jù)庫(kù)數(shù)據(jù):

clip_image020

可以看到RoleID為“71DFA…”的關(guān)系被刪除了,而且新建了一個(gè)RoleID為“3F45B…”的關(guān)系,而RoleID為“63B04…”的關(guān)系沒(méi)有發(fā)生改變。操作成功完成。

刪除所有關(guān)系

在本次操作中,將馬六的全部角色置空。

clip_image022

點(diǎn)擊保存后,查看數(shù)據(jù)庫(kù)數(shù)據(jù):

clip_image024

可以看到用戶的關(guān)系被全部刪除了。至此,測(cè)試工作告一段落,開(kāi)始介紹功能是如何完成的。

在點(diǎn)擊保存按鈕時(shí),要做的就是將選中的用戶,以及為其配置的角色保存到數(shù)據(jù)庫(kù)中。有過(guò)這樣的開(kāi)發(fā)經(jīng)驗(yàn)的開(kāi)發(fā)人員會(huì)知道這個(gè)過(guò)程還是十分繁瑣的,在下面的代碼中,我將使用設(shè)計(jì)后的方式來(lái)完成這個(gè)操作:

  1. /// <summary>  
  2. /// 點(diǎn)擊保存按鈕時(shí)的操作  
  3. /// </summary>  
  4. protected void btnSave_Click(object sender, EventArgs arg)  
  5. {  
  6. Users user = DataContext.Users.SingleOrDefault(e => e.UserID == new Guid(ddlUsers.SelectedValue));  
  7.     List<Roles> roles = new List<Roles>();  
  8.     foreach (ListItem item in cblUserRoles.Items)  
  9.     {  
  10.         if (item.Selected)  
  11.         {  
  12.     Roles role = DataContext.Roles.SingleOrDefault(e => e.RoleID == new Guid(item.Value));  
  13.             if (role != null)  
  14.             {  
  15.                 roles.Add(role);  
  16.             }  
  17.         }  
  18.     }  
  19.     LinqM2MProvider.Execute(user, roles, true);  

可以看到,除了封裝參數(shù)(用戶對(duì)象,角色對(duì)象集合)的常規(guī)操作外,只調(diào)用了一個(gè)方法:LinqM2MProvider.Execute(user, roles, true)。那么這個(gè)LinqM2MProvider是什么呢?答案是一個(gè)接口,下面的代碼介紹了這個(gè)接口的構(gòu)造方法:

  1. /// <summary>  
  2. /// 管理用戶-用戶角色-角色之間關(guān)系的提供程序  
  3. /// </summary>  
  4. public ILinqM2MProvider<Users, UsersInRoles, Roles> LinqM2MProvider  
  5. {  
  6.     get 
  7.     {  
  8.         var provider = new LinqM2MProvider<Users, UsersInRoles, Roles>()  
  9.         {  
  10.             DataContext = this.DataContext,  
  11.  GetRelationHandler = (m, s) => DataContext.UsersInRoles.SingleOrDefault(e => e.UserID == m.UserID && e.RoleID == s.RoleID),  
  12.             RelationSetHandler = m => m.UsersInRoles,  
  13.             CreateRelationHandler = (m, s) => new UsersInRoles()  
  14.             {  
  15.                 UserInRoleID = Guid.NewGuid(),  
  16.                 Users = m,  
  17.                 Roles = s  
  18.             }  
  19.         };  
  20.         return provider;  
  21.     }  

可以看到ILinqM2MProvider接口是一個(gè)泛型接口,它的三個(gè)泛型類型是用戶-用戶角色-角色,就跟本文“名詞解釋”段落中的圖片所顯示關(guān)系一致。使用它需要設(shè)置四個(gè)屬性:

l  DataContext

l  GetRelationHandler

l  RelationSetHandler

l  CreateRelationHandler

那么這個(gè)四個(gè)屬性分別代表什么含義呢?下文將進(jìn)行詳細(xì)的說(shuō)明。

接口ILinqM2MProvider<M, R, S>

定義

  1. /// <summary> 
  2. /// 維護(hù)LINQ to SQL的多對(duì)多關(guān)聯(lián)關(guān)系  
  3. /// </summary> 
  4. /// <typeparam name="M">主表類型</typeparam> 
  5. /// <typeparam name="R">關(guān)系表類型</typeparam> 
  6. /// <typeparam name="S">從表類型</typeparam> 
  7. /// <remarks> 
  8. /// Sunny D.D at 2010-8-20  
  9. /// sunny19788989@gmail.com  
  10. /// </remarks> 
  11. public interface ILinqM2MProvider<M, R, S> 
  12.     where M : class  
  13.     where R : class  
  14.     where S : class  
  15. {  
  16.     /// <summary> 
  17.     /// LINQ to SQL入口  
  18.     /// </summary> 
  19.     DataContext DataContext { get; set; }  
  20.     /// <summary> 
  21.     /// 描述如何根據(jù)主表對(duì)象和從表對(duì)象獲取中間關(guān)系表對(duì)象的行為  
  22.     /// </summary> 
  23.     Func<M, S, R> GetRelationHandler { get; set; }  
  24.     /// <summary> 
  25.     /// 描述如何根據(jù)主表對(duì)象和從表對(duì)象創(chuàng)建中間關(guān)系表對(duì)象的行為  
  26.     /// </summary> 
  27.     Func<M, S, R> CreateRelationHandler { get; set; }  
  28.     /// <summary> 
  29.     /// 描述如何根據(jù)主表對(duì)象獲取獲取中間關(guān)系表對(duì)象集合  
  30.     /// </summary> 
  31.     Func<M, EntitySet<R>> RelationSetHandler { get; set; }  
  32.     /// <summary> 
  33.     /// 獲取將要?jiǎng)h除的關(guān)系  
  34.     /// </summary> 
  35.     /// <param name="master">主表對(duì)象</param> 
  36.     /// <param name="slaves">從表對(duì)象</param> 
  37.     /// <returns></returns> 
  38.     IEnumerable<R> GetDeleting(M master, IEnumerable<S> slaves);  
  39.     /// <summary> 
  40.     /// 獲取將要新建的關(guān)系  
  41.     /// </summary> 
  42.     /// <param name="master">主表對(duì)象</param> 
  43.     /// <param name="slaves">從表對(duì)象</param> 
  44.     /// <returns></returns> 
  45.     IEnumerable<R> GetAdding(M master, IEnumerable<S> slaves);  
  46.     /// <summary> 
  47.     /// 執(zhí)行操作。默認(rèn)在方法結(jié)束時(shí)不將變更提交至數(shù)據(jù)庫(kù),需要顯式提交變更。  
  48.     /// </summary> 
  49.     /// <param name="master">主表對(duì)象</param> 
  50.     /// <param name="slaves">從表對(duì)象</param> 
  51.     void Execute(M master, IEnumerable<S> slaves);  
  52.     /// <summary> 
  53.     /// 執(zhí)行操作  
  54.     /// </summary> 
  55.     /// <param name="master">主表對(duì)象</param> 
  56.     /// <param name="slaves">從表對(duì)象</param> 
  57.     /// <param name="isSubmitChanges">是否在方法結(jié)束時(shí)將變更提交至數(shù)據(jù)庫(kù)</param> 
  58.     void Execute(M master, IEnumerable<S> slaves, bool isSubmitChanges);  

DataContext屬性

類型:System.Data.Linq.DataContext

RelationSetHandler屬性

描述如何根據(jù)主表對(duì)象獲取獲取中間關(guān)系表對(duì)象集合。

在LINQ to SQL架構(gòu)中,一個(gè)表的外鍵對(duì)象集合是用EntitySet來(lái)表示的,EntitySet中的元素代表著主鍵表關(guān)聯(lián)的外建表的條目。在本文的“測(cè)試用例”部分中,是這樣賦值的:

RelationSetHandler = m => m.UsersInRoles

GetRelationHandler屬性

描述如何根據(jù)主表對(duì)象和從表對(duì)象獲取中間關(guān)系表對(duì)象的行為。在本文中,就是根據(jù)用戶ID與角色I(xiàn)D獲取一個(gè)UsersInRoles對(duì)象。

它的作用是確定有多少個(gè)中間表對(duì)象需要被操作。當(dāng)然,最后提交至數(shù)據(jù)庫(kù)的元素,是與RelationSetHandler操作結(jié)果中包含的元素進(jìn)行比對(duì)后才被執(zhí)行的。在本文的“測(cè)試用例”部分中,是這樣賦值的:

GetRelationHandler = (m, s) => DataContext.UsersInRoles.SingleOrDefault(e => e.UserID == m.UserID && e.RoleID == s.RoleID)

CreateRelationHandler屬性

描述如何根據(jù)主表對(duì)象和從表對(duì)象創(chuàng)建中間關(guān)系表對(duì)象的行為。

在傳遞的從表集合中,發(fā)現(xiàn)有需要新建的關(guān)系時(shí),就要用到這個(gè)操作。在本文的“測(cè)試用例”部分中,是這樣賦值的:

  1. CreateRelationHandler = (m, s) => new UsersInRoles()  
  2. {  
  3.     UserInRoleID = Guid.NewGuid(),  
  4.     Users = m,  
  5.     Roles = s  

GetDeleting方法

獲取將要?jiǎng)h除的關(guān)系。

GetAdding方法

獲取將要新建的關(guān)系。

Execute方法

執(zhí)行操作。

接口的實(shí)現(xiàn)LinqM2MProvider<M, R, S>

至于接口的實(shí)現(xiàn),各位肯定都有自己的方式,在這里我就不詳細(xì)說(shuō)明了,本文給出一個(gè)實(shí)現(xiàn)僅供參考。下載地址:https://docs.google.com/leaf?id=0B9T0APtVi1fyNGE3ODA5YjctZmIwZC00MjU3LTg5NmYtNGIxZWI0OGI1OTkz&hl=zh_CN

總結(jié)

使用本文中介紹的方式來(lái)管理多對(duì)多表間關(guān)系,就可以不關(guān)注操作到底是進(jìn)行添加關(guān)系、刪除關(guān)系、還是更改關(guān)系了,開(kāi)發(fā)人員需要做的只是將三個(gè)委托GetRelationHandler、CreateRelationHandler、RelationSetHandler構(gòu)造好,并傳遞正確的參數(shù)(主表對(duì)象、從表集合)即可,從而不再關(guān)注操作細(xì)節(jié),提高開(kāi)發(fā)效率。

原文標(biāo)題:維護(hù)LINQ to SQL多對(duì)多表間關(guān)系

鏈接:http://www.cnblogs.com/sunnycoder/archive/2010/08/22/1805875.html

【編輯推薦】

  1. Linq匿名類型簡(jiǎn)單概述
  2. Linq隨機(jī)讀取數(shù)據(jù)淺析
  3. Linq Lambda表達(dá)式全面分析
  4. Linq擴(kuò)展方法簡(jiǎn)單分析
  5. 初探Linq局部變量類型
責(zé)任編輯:彭凡 來(lái)源: 博客園
相關(guān)推薦

2009-09-17 17:34:23

linq to sql

2009-09-15 10:35:11

linq多表查詢

2009-09-15 13:28:49

LINQ表間關(guān)系查詢

2009-09-17 17:14:54

linq to sql

2009-09-17 18:05:15

linq to sql

2009-09-15 11:29:04

LINQ to SQL

2010-10-21 11:10:57

SQL Server查

2009-06-04 16:14:22

Hibernate一對(duì)Hibernate一對(duì)Hibernate多對(duì)

2009-06-18 14:22:06

Hibernate多對(duì)Hibernate

2009-06-03 16:27:27

Hibernate一對(duì)一關(guān)系

2021-03-16 09:23:25

VueMixin模塊

2010-10-08 13:56:32

2010-07-01 12:56:07

SQL Server表

2009-09-09 16:07:16

Linq實(shí)體關(guān)系

2009-09-16 09:56:42

LINQ to SQL

2021-04-12 18:14:56

鴻蒙HarmonyOS應(yīng)用開(kāi)發(fā)

2009-09-08 14:45:24

Linq to SQL支持SQL Serve

2023-06-12 08:09:01

FlaskSQLAlchemy

2009-09-18 13:23:27

Northwind對(duì)象LINQ to SQL

2009-09-08 13:07:15

介紹Linq to S
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)