注:本文针对的是 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. Monocular Vision

    Monocular Vision: a condition in which one eye is blind, seeing with only one eye Binocular Vision:  ...

  2. HNOI2006-鬼谷子的钱袋

    鬼谷子的钱袋 鬼谷子非常聪明,正因为这样,他非常繁忙,经常有各诸侯车的特派员前来向他咨询时政.有一天,他在咸阳游历的时候,朋友告诉他在咸阳最大的拍卖行(聚宝商行)将要举行一场拍卖会,其中有一件宝物引起 ...

  3. HDU 1027 Ignatius and the Princess II(康托逆展开)

    Ignatius and the Princess II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ( ...

  4. jpg 批量压缩工具 v1.0

    工作需要经常压缩大量图片,网上搜了一些  使用起来总觉得不方便.昨天自己用AIR 写了一个,功能简单,需要的朋友可以自己 下载使用win 版绿色版  http://pan.baidu.com/s/1k ...

  5. Xstream 学习地址

    http://forestqqqq.iteye.com/category/301129

  6. namespace使用总结

    1.防止引用文件中函数名相同,导致函数重定义错误: //test1.php <?php namespace foo; function func(){ echo "test1/func ...

  7. iOS - UIProgressView

    前言 NS_CLASS_AVAILABLE_IOS(2_0) @interface UIProgressView : UIView <NSCoding> @available(iOS 2. ...

  8. xml配置文件详解

    1:bean的基本属性配置: <!-- id是bean的标识符,必须唯一,如果没有配置id,name默认为标识符 如果配置了id,有配置了name,那么name为别名 name可以设置多个别名, ...

  9. The specified child already has a parent错误

    10-05 23:39:48.187: E/AndroidRuntime(12854): Caused by: java.lang.IllegalStateException: The specifi ...

  10. Android 热补丁动态修复框架小结

    一.概述 最新github上开源了很多热补丁动态修复框架,大致有: https://github.com/dodola/HotFix https://github.com/jasonross/Nuwa ...