注:本文针对的是 Entity Framework Code First 场景。

之前写过三篇文章试图理清Entity Framework中的一对一关系(单相思(单向一对一), 两情相悦(双向一对一), 两情相悦-续),但当时理得不够清,新的一年重新理一理。

当时“一对一”的实体关系,对应的数据库关系是外键关联(实际上是一种“一对多”关系,所以映射时用了WithMany)。而数据库中的“一对一”关系是共享主键(这是我个人的理解,不妥之处,欢迎指出),下篇文章将要理的就是这个关系。

由于双向“一对一”关系很少用到,而且不推荐使用,为了更清楚地理解,我们这里只谈单向一对一关系,也就是“基于外键关联的单向一对一关系(One-to-one Unidirectional relationships)”,对应的之前的文章是单相思(单向一对一)

1. 类图

2. 类的定义

public class BlogSite {     public int BlogID { get; set; }     public string BlogApp { get; set; }     public bool IsActive { get; set; }     public Guid UserID { get; set; }         public virtual BlogUser BlogUser { get; set; } }
public class BlogUser {     public Guid UserID { get; set; }     public string Author { get; set; }     public int BlogID { get; set; } }

3. 数据库结构

4. Enitity Framework映射关系定义

protected override void OnModelCreating(DbModelBuilder modelBuilder) {     modelBuilder.Entity<BlogSite>()         .HasRequired(b => b.BlogUser)         .WithMany(); }

怎么理解这里的HasRequired与WithMany呢?

我的理解是:HasRequired是针对BlogSite与BlogUser的关系,WithMany是针对BlogUser与BlogSite的关系。.HasRequired(b => b.BlogUser).WithMany()表示BlogSite与BlogUser存在Required关联关系(One-To-One, 每一个BlogSite都有一个对应的BlogUser),而这个关联对BlogUser来说是One-To-Many(一个BlogUser可以有多个BlogSite)。

你也许会疑惑?明明是单向一对一的实体关系,这里怎么弄出个一对多的关系?

如果有这样的疑惑,属正常现象,我从去年7月份写那篇文章开始疑惑,一直疑惑到现在,写篇文章时才有点搞明白。

注意,“单向一对一”是什么?是实体关系;Entity Framework是什么?是O/RM,是用来映射实体关系与数据库关系;还少了什么?数据库关系。

从上面的图中的数据库结构可以看出,BlogSite与BlogUser之间是外键关联关系,下面的图可以更清楚地看出这一点。

这个外键关联表示的就是BlogUser与BlogSite之间是一对多的数据库关系。

总结一下:

实体关系 —— BlogSite与BlogUser之间的单向一对一

数据库关系 —— BlogUser与BlogSite之间的一对多

是不是这样呢?Entity Framework是不是也是这样认为的呢?我们来验证一下。

怎么知道Entity Framework的想法呢?

通过EDM。

可这里是Code First?

不管什么First,都有EDM,因为这是Entity Framework的地图,没有它,Entity Framework就会晕头转向。Code First的EDM是在EF运行时生成的,不是没有地图,只是在Entity Framework的心中,我们看不到而已。

怎么让Entity Framework说出心里话呢?

从Morteza Manavi大师那学到一招,代码如下:

using (var context = new Context()) {     XmlWriterSettings settings = new XmlWriterSettings();     settings.Indent = true;       using (XmlWriter writer = XmlWriter.Create(@"Model.edmx", settings))     {         EdmxWriter.WriteEdmx(context, writer);     }                             }

通过上面的代码,你就可以拿到EF心中的地图 —— edmx文件。请看地图:

果然,EF心中的地图就是BlogUser与BlogSite的一对多关系。地图的作用是什么?是让EF通过地图在数据库找到对应的数据。地图是如何产生的?是我们通过FluentAPI告诉Entity Framework:.HasRequired(b => b.BlogUser).WithMany()。

我们再来剖析一下.HasRequired(b => b.BlogUser).WithMany()。

之前,我一直被困扰,是因为总是把这里的定义当作实体的关系的定义。错!这里虽然用的是实体进行定义,但定义的是实体与数据库中的数据之间的映射关系(这本来就是常识,竟然被忽略了),更多的是告诉EF这些实体在数据库中的数据关系。EF最终是根据这个定义生成相应的SQL。

那我们从生成查询SQL的角度来理解一下:

.HasRequired(b => b.BlogUser)告诉EF,这是一个INNER JOIN查询(BlogSite INNER JOIN BlogUser);但INNER JOIN还需要条件,WithMany()告诉EF这是一个外键关联,EF据此进行推断,从BlogUser中找到主键UserID,并检查BlogSite中是否存在名为UserID的属性,如果存在,就以此为外键进行查询。而我们的BlogSite中有UserID,于是生成下面的SQL:

SELECT  [Extent1].[BlogID] AS [BlogID],  [Extent1].[BlogApp] AS [BlogApp],  [Extent1].[IsActive] AS [IsActive],  [Extent1].[UserID] AS [UserID],  [Extent2].[UserID] AS [UserID1],  [Extent2].[Author] AS [Author] FROM  [dbo].[BlogSite] AS [Extent1] INNER JOIN [dbo].[BlogUser] AS [Extent2] ON [Extent1].[UserID] = [Extent2].[UserID] WHERE 1 = [Extent1].[IsActive]

小结

理清“基于外键关联的单向一对一关系”,关键在于对modelBuilder.Entity<A>().HasRequired(A => A.B).WithMany()的理解。

我再来理解一次:

.HasRequired(A => A.B) 表示:1)实体A与实体B是一对一关系,实体A有一个导航属性A.B;2)在数据库中表A与表B存在一对一关联(INNER JOIN)。

.WithMany() 表示:1) 实体B与实体A可以没有关系,也可以是一对多关系;2)在数据库中表A与表B存在外键关联。

上面全是我的个人理解,真正理清Entity Framework中的关系需要大家的力量,我只是抛个砖。

除了“基于外键关联的单向一对一关系”,还有“基于共享主键的单向一对一关系”,这也是我们开发中经常碰到的一种关系,比如博客文章(BlogPost)与文章内容(PostBody),新闻(NewsItem)与新闻内容(NewsBody)。下一篇文章将会理理这个关系。

Entity Framework - 理清关系 - 基于外键关联的单向一对一关系的更多相关文章

  1. Entity Framework - 基于外键关联的单向一对一关系

    代码的世界,原以为世界关系很简单,确道是关系无处不在.NET世界里ORM框架中EntityFramework作为其中翘楚,大大解放了搬砖工作的重复工作,着实提高了不少生产力,而也碰到过不少问题!比如关 ...

  2. Entity Framework Code First主外键关系映射约定

    本篇随笔目录: 1.外键列名默认约定 2.一对多关系 3.一对一关系 4.多对多关系 5.一对多自反关系 6.多对多自反关系 在关系数据库中,不同表之间往往不是全部都单独存在,而是相互存在关联的.两个 ...

  3. Entity Framework 实体间的外键关系

    EF 默认是开户级联删除的,这此规则将会删除非空外键和多对多的关系,如果 在数据库上下文中的实体模型类 存在着 级联引用和多重删除路径,那么EF就抛出 级联引用和多重删除路径的异常. Introduc ...

  4. Hibernate,关系映射的多对一单向关联、多对一双向关联、一对一主键关联、一对一外键关联、多对多关系关联

    2018-11-10  22:27:02开始写 下图内容ORM.Hibernate介绍.hibername.cfg.xml结构: 下图内容hibernate映射文件结构介绍 下图内容hibernate ...

  5. 《Entity Framework 6 Recipes》中文翻译系列 (29) ------ 第五章 加载实体和导航属性之过滤预先加载的实体集合和修改外键关联

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-13  过滤预先加载的实体集合 问题 你想过滤预先加载的实体集合,另外,你想使用 ...

  6. Hibernate 再接触 关系映射 一对一单向外键关联

    对象之间的关系 数据库之间的关系只有外键 注意说关系的时候一定要反面也要说通 CRUD 数据库之间设计 主键关联 单向的外键关联 中间表 一对一单向外键关联 Husband.java package ...

  7. hibernate笔记--基于外键的单(双)向的一对一映射关系

    假设我们有两张表,人员信息表Person,和身份信息表IdCard,我们知道每个人只有一个身份证号,所以这里的Person和IdCard表是一一对应的,也就是一对一的映射关系,基于外键的单向一对一映射 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-13  在基类中应用条件 问题 你想从一个已存在的模型中的实体派生一个新的实体, ...

  9. Entity FrameWork对有外键关联的数据表的添加操作

    前天做了一个MVC Entity FrameWork项目,遇到有外键关联的数据编辑问题.当你编辑的时候,按照正常的逻辑,把每个字段的数据都对号入座了,然后点击保存按钮,本以为会顺理成章的编辑数据,但是 ...

随机推荐

  1. CSS笔记(十)position属性与定位

    参考:http://www.w3school.com.cn/cssref/pr_class_position.asp position属性规定了元素的定位类型.任何元素都可定位,其中,绝对或固定元素会 ...

  2. random使用

    package com.cz.test; import java.util.Random; public class RandomTest { public static void main(Stri ...

  3. Git 的origin和master分析 push/diff/head(转)

    1.origin/master : 一个叫 origin 的远程库的 master 分支 2.HEAD指向当前工作的branch,master不一定指向当前工作的branch 3.git  push ...

  4. poj1319Pipe Fitters

    链接 算不上几何的水题 第一种为(int)a*(int)b: 第二种分宽高交换两种讨论. 每一个的高度除第一个为1外其它的都可以看着b/sqrt(3.0)/2; #include <iostre ...

  5. mysql 编码测试

    insert into t1(v1) values('cn中国'); select * from t1; 1.输入gbk,交互latin1,数据库latin1 insert,客户端把gbk的输入当成l ...

  6. D3.js 插入元素,删除元素

    插入元素涉及的函数有两个: 一.append():在选择集末尾插入元素 假设有三个段落元素 <p>Apple</p> <p>Pear</p> <p ...

  7. CSS3_边框属性之圆角

    一.border-radius是向元素添加圆角边框: border-radius的值不仅能用px单位,你还可以用百分比或者em,但兼容性目前还不太好.(都不能是负值) 1.border-radius ...

  8. vim 空格和换行的删除和替换

      %s/\s//g %s/\r//g %s/\n//g   把一个很长的一行按空格分为多行 :%s/ +/\r/g简单解释一下:%s :在整个文件范围查找替换/ :分隔符+ :匹配空格,其中“ ”表 ...

  9. angular-file-upload 中文API

    github地址: https://github.com/nervgh/angular-file-upload Directives(指令) nv-file-drop <!-- 最少配置 --& ...

  10. Sql Server中通配符的使用

    Sql Server中通配符的使用 通配符_ "_"号表示任意单个字符,该符号只能匹配一个字符."_"可以放在查询条件的任意位置,且只能代表一个字符.一个汉字只 ...