zoukankan      html  css  js  c++  java
  • Entity Framework 理清关系 基于外键关联的单向一对一关系

    注:本文针对的是 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)。下一篇文章将会理理这个关系。

  • 相关阅读:
    Java 实现 Word 文档分栏效果
    Java 在PPT中添加SmartArt图形
    Java 创建 Excel 数据透视表
    Java分布式架构下如何实现分布式锁
    为什么选择学习Java语言的人越来越多?
    浅析JAVA中VO、DTO、DO、PO的了解
    Java基础之何为动态代理?
    Java三大框架是什么?
    android 系统裁剪 ​
    java怎么就能跨平台了呢
  • 原文地址:https://www.cnblogs.com/dudu/p/entity_framework_one_to_one_unidirectional.html
Copyright © 2011-2022 走看看