在C#3.0入门系列(十)-之Join操作一文中,我们提到了M:M 的关系中的join操作。哦,原来,M:M 的关系在数据库中,依然是通过1:M 来体现。比如,在一个域内,一个User可以加入到多个Group中,一个Group也可以包含多个User。 User与Group并没有直接的关系,而是通过第三个表UserInGroup发生关系。User与 UserInGroup的关系为1:M,其关系键为UserId, 而Group与 UserInGroup的关系也为1:M, 其关系键为GroupId,这样,我们通过第三个表,让User与Group发生了关系,他们的关系为 M:M.
这三个表的脚本如下:
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[User]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1) BEGIN CREATE TABLE [dbo].[User]( [UserId] [nchar](10) NOT NULL, [UserName] [nchar](10) NULL, CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ( [UserId] ASC ) ON [PRIMARY] ) ON [PRIMARY] END GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[Group]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1) BEGIN CREATE TABLE [dbo].[Group]( [GroupId] [nchar](10) NOT NULL, [GroupName] [nchar](10) NULL, CONSTRAINT [PK_Group] PRIMARY KEY CLUSTERED ( [GroupId] ASC ) ON [PRIMARY] ) ON [PRIMARY] END GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[UserInGroup]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1) BEGIN CREATE TABLE [dbo].[UserInGroup]( [UserId] [nchar](10) NOT NULL, [GroupId] [nchar](10) NOT NULL, CONSTRAINT [PK_UserInGroup] PRIMARY KEY CLUSTERED ( [UserId] ASC, [GroupId] ASC ) ON [PRIMARY] ) ON [PRIMARY] END GO IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_UserInGroup_Group]') AND type = 'F') ALTER TABLE [dbo].[UserInGroup] WITH CHECK ADD CONSTRAINT [FK_UserInGroup_Group] FOREIGN KEY([GroupId]) REFERENCES [dbo].[Group] ([GroupId]) GO ALTER TABLE [dbo].[UserInGroup] CHECK CONSTRAINT [FK_UserInGroup_Group] GO IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID(N'[dbo].[FK_UserInGroup_User]') AND type = 'F') ALTER TABLE [dbo].[UserInGroup] WITH CHECK ADD CONSTRAINT [FK_UserInGroup_User] FOREIGN KEY([UserId]) REFERENCES [dbo].[User] ([UserId]) GO ALTER TABLE [dbo].[UserInGroup] CHECK CONSTRAINT [FK_UserInGroup_User]
他们的关系图如下:
创建数据库后,添加一些数据供测试。
insert into [User] values('Tom Song','Tom Song') insert into [User] values('Guoan Song','Guoan Song') insert into [Group] values ('Csharp','Csharp Team') insert into [Group] values ('Dlinq','Dlinq Team') insert into UserInGroup values ('Tom Song','Csharp') insert into UserInGroup values ('Tom Song','Dlinq') insert into UserInGroup values ('Guoan Song','Csharp') insert into UserInGroup values ('Guoan Song','Dlinq')
使用OR Designer将他们映射为实体。关于OR Designer请参考C#3.0入门系列(七)--之OR工具介绍
现在的问题是:User和Group的实体对象中,可不可以直接引用对方呢?就像User.Groups 或Group.Users。我们可不可以去改变其映射,直接越过UserInGroup,让User和Group直接发生关系呢?回答是肯定的。但是,数据库中,依然是三个表。你不可能在数据库中越过表UserInGroup的。表UserInGroup起了一个纽带的作用,想把它抛弃掉,不太可能。那可不可以,在mapping code中,做些手脚,让Linq To Sql自己去找这个纽带呢?回答是,Linq To Object可以,但是, Linq To Sql不可以。
为什么Linq To Sql不可以?其原因就是Linq To Sql需要先翻译成Sql语句,而,这个映射,必须真实反映数据库里表的情况。也就说,这个映射,无法逾越UserInGroup实体。它必须要有UserInGroup。
那Linq To Object怎么样可以呢?把下面的代码,加入到你的工程中。
using System.Data.Linq; using System.Data.Linq.Mapping; using System.Data; using System.Collections.Generic; using System.Reflection; using System.Linq; using System.Linq.Expressions; using System.Runtime.Serialization; using System.ComponentModel; using System; namespace ConsoleApplication1 { public partial class Group { public List<User> Users { get { return (from u in this.UserInGroups select u.User).ToList(); } } } public partial class User { public List<Group> Groups { get { return (from g in this.UserInGroups select g.Group ).ToList(); } } } }
我们来做个测试,看看是不是成功了呢。
public static void Main(string[] arg) { DataClasses1DataContext db = new DataClasses1DataContext(); db.Log = Console.Out; var userSet = (from u in db.Users select u).ToList(); foreach (var use in userSet) { foreach (var group in use.Groups) { Console.WriteLine(group.GroupName); } } var groupSet = (from u in db.Groups select u).ToList(); foreach (var group in groupSet) { foreach (var user in group.Users) { Console.WriteLine(user.UserName); } } }
var q = (from u in db.Users from g in u.Groups select new { u.UserName, g.GroupName }).ToList();
var q2 = (from u1 in (from u in db.Users select u).ToList() from g in u1.Groups select new { u1.UserName, g.GroupName }).ToList();
还可以使用下面的这个映射code。
using System.Data.Linq; using System.Data.Linq.Mapping; using System.Data; using System.Collections.Generic; using System.Reflection; using System.Linq; using System.Linq.Expressions; using System.Runtime.Serialization; using System.ComponentModel; using System; namespace ConsoleApplication1 { public partial class Group { public IEnumerable<User> Users { get { return from u in this.UserInGroups select u.User; } } } public partial class User { public IEnumerable<Group> Groups { get { return from g in this.UserInGroups select g.Group; } } } }
本文探讨了LinqToSql中如何处理多对多关系,通过具体实例介绍了如何利用UserInGroup作为纽带建立User与Group之间的联系,并演示了如何在C#中通过LINQ实现这种关系。
1281

被折叠的 条评论
为什么被折叠?



