Linq To Sql进阶系列(一) 一文中,我们谈到了数据库中的两种基本关系1:M 与1:1. 而现实世界中,还有一种M:M 的关系。比如,一个老师可以有多个学生,而一个学生也可以有多个老师。老师和学生的关系就是多对多的关系。这些关系在数据库中是如何反映的呢?
在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();
            }
        }
    }
}

为了不破坏数据库的映射,我们把这部分改动放到partial  class中。这样,我们渴望实现user.Group。
我们来做个测试,看看是不是成功了呢。


    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();

编译通过,在run-time时,出错。因为,Linq To Sql不知道该怎么去找这个关系。那么下面这个呢?

        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();

run-time没有问题。纠起原因,其在里面已经取回了数据,是Linq To Object的范畴了。

还可以使用下面的这个映射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;
            }
        }
    }
}

结合我们的测试例子,请大家仔细比较他们的区别哦。前面那个是一次性取出了。后面这个是用那个取那个。

TrackBack:http://www.cnblogs.com/126/archive/2007/07/31/836306.html

转载于:https://www.cnblogs.com/hdjjun/archive/2008/11/05/1327125.html

Linq To Sql进阶系列(二)M:M关系相关推荐

  1. Linq To Sql进阶系列 -目录导航

    博客园CLR基础研究团队|CLR团队精品系列|C# 3.0专题 [Linq To Sql进阶系列] 目录导航 1 Linq To Sql进阶系列(一)-从映射讲起 本系列,或多或少,直接或间接依赖入门 ...

  2. Linq To Sql进阶系列(七)动态查询续及CLR与SQL在某些细节上的差别

    在上面一篇文章Linq To Sql进阶系列(六)中,我们提到了使用object的动态查询.本文在上文的基础上,再做更加深入的引申.同时修正上文中一些不妥的地方. 1, object的动态查询续 首先 ...

  3. .NET深入实战系列—Linq to Sql进阶

    .NET深入实战系列-Linq to Sql进阶 最近在写代码的过程中用到了Linq查询,在查找资料的过程中发现网上的资料千奇百怪,于是自己整理了一些关于Linq中容易让人困惑的地方. 本文全部代码基 ...

  4. Wireshark入门与进阶系列(二)

    摘自http://blog.csdn.net/howeverpf/article/details/40743705 Wireshark入门与进阶系列(二) "君子生非异也,善假于物也&quo ...

  5. matlab 积分进阶教程,最适合小白的matlab教程系列_进阶系列二之微积分

    微积分篇 更多文章参考 符号变量 极限问题 求导数 求导数----偏导数 积分--符号解 积分数值解 多重积分 级数求和 泰勒级数展开 常微分方程 更多文章参考 最适合小白的matlab教程系列_基础 ...

  6. 最适合小白的matlab教程系列_进阶系列二之微积分

    微积分篇 更多文章参考 符号变量 极限问题 求导数 求导数----偏导数 积分--符号解 积分数值解 多重积分 级数求和 泰勒级数展开 常微分方程 更多文章参考 最适合小白的matlab教程系列_基础 ...

  7. 最适合小白的matlab教程系列_进阶系列二之多项式

    多项式 一维插值 二维插值 计算多项式 *计算多项式* 计算多项式乘除法 多项式求导 多项式求积分 多项式曲线拟合 一维插值 命名格式vq=interp1(x,v,xq) x:原始数据(自变量)n维向 ...

  8. 浅谈LINQ to SQL集成数据库语言优劣

    Linq To SQL是Microsoft开发的针对解决data!=object问题的新技术.在笔者的一系列的文章中,对它已经做了大量的介绍.现在,笔者将从经验的角度,谈谈它的优劣. 1.LINQ t ...

  9. vivado路径最大时钟约束_Vivado使用误区与进阶系列(五)XDC约束技巧之I/O篇(下)...

    XDC约束技巧之CDC篇 继<XDC 约束技巧之 I/O 篇(上) >详细描述了如何设置 Input 接口约束后,我们接着来聊聊怎样设置 Output 接口约束,并分析 UCF 与 XDC ...

最新文章

  1. ASP中的常用服务器检测源码
  2. 人工智能将如何改变芯片设计
  3. Nginx防盗链、访问控制、Nginx解析PHP相关配置、Nginx代理
  4. 纸质图书与电子图书的营销策略研究
  5. Halcon算子:min_max_gray和gray_histo的区别
  6. UART串口通信浅谈之(一)--基础概述
  7. 最小拍控制系统详细解读(阶跃输入+速度输入2个案例)【Simulink仿真】
  8. 华东电脑申威服务器_华东电脑(600850):申威服务器首批量产下线 国产化业务落地里程碑事件[配资公司会议室]...
  9. javascript 的module 模块化
  10. Android 中ListView带复选框多选、全选、不选处理
  11. 编译问题解决:mkdir: 无法创建目录/usr/local/share/man/man1: 文件已存在
  12. Atitit. 提升存储过程与编程语言的可读性解决方案v3 qc25.docx
  13. C# AForge视频录像
  14. php 仿安居客源码_python抓取安居客小区数据的程序代码
  15. 综述 | 近年来深度学习的重要研究成果(附PDF)
  16. CuteFTP Pro v8.3.1 (Build 08.07.2008.1) - patch - PakMan / Team SnD
  17. 服务器桌面假死怎么处理,只需一分钟轻松搞定Win7桌面假死问题
  18. 有个空间,名叫 Gamma
  19. 商城前端模板_如何理解微信小程序和微商城,微信公众号以及APP之间的关系?一张图看懂了!...
  20. 宏基因组分析-基于binning

热门文章

  1. [转载] Python 完整实现的简单遗传算法(SGA)
  2. [转载] python之flask框架
  3. 读美国教授写给被开除中国留学生的信感悟
  4. js中去掉字符串中的某个指定字符
  5. Unity3D AssetBundle相关
  6. Seek the Name, Seek the Fame - POJ 2752(next运用)
  7. 2.C#面向对象基础属性
  8. Linux下的Latex安装和中文支持
  9. 自动化登陆博客园脚本
  10. zz 传苹果平板电脑的UI界面将具备“快速学习”功能