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)。下一篇文章将会理理这个关系。

转载于:https://www.cnblogs.com/liangxiaofeng/p/5810500.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372432.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信社交小程序服务器,Day12-微信小程序实战-交友小程序-搭建服务器与上传文件到后端...

要搞一个小型的cms内容发布系统因为小程序上线之后&#xff0c;直接对数据库进行操作的话&#xff0c;慧出问题的&#xff0c;所以一般都会做一个管理系统&#xff0c;让工作人员通过这个管理系统来对这个数据库进行增删改查微信小程序其实给我们提供了这样的能力了(也就是可以…

java go

熟练掌握java技术&#xff0c;对多线程、数据结构有清晰的认识&#xff1b; 熟悉MySQL/Oracle数据库&#xff0c;熟悉关系数据库应用设计开发&#xff1b; 熟悉Spring/MyBatis/Freemarker等一种或者多种框架&#xff1b; java基础扎实&#xff0c;熟练掌握目前主流的开源框架&a…

了解如何解决OSGI捆绑包

我想回顾一下OSGI包如何解决并使用Apache Karaf进行演示。 Karaf是基于Apache Felix内核的功能齐全的OSGI容器&#xff0c;并且是Apache ServiceMix集成容器的基石。 对于第一部分&#xff0c;我将讨论OSGI框架如何解决捆绑包。 在第二部分中&#xff0c;我将使用Apache Karaf演…

文件共享服务器imac,iMac怎么在网络上共享设备windows文件夹和服务 | MOS86

本章通过向您展示如何在网络和Mac和Windows计算机之间共享文件&#xff0c;文件夹和设备&#xff0c;帮助您充分利用您的iMac网络连接。→使用Macs共享文件和文件夹使用AirDrop和文件共享→与Windows 7计算机共享文件→设置共享权限→使用共享表快速在线共享文件→共享和访问网…

【转】 简单理解Socket

题外话 前几天和朋友聊天&#xff0c;朋友问我怎么最近不写博客了&#xff0c;一个是因为最近在忙着公司使用的一些控件的开发&#xff0c;浏览器兼容性搞死人&#xff1b;但主要是因为这段时间一直在看html5的东西&#xff0c;看到web socket时觉得很有意思&#xff0c;动手写…

.NET基础

.NET C# ASP.NET关系&#xff1a;.NET是一个平台&#xff0c;提供程序运行的虚拟机环境和类库。 C#是.Net平台上的一种语言&#xff0c;其他语言还有VB.NET PowerShell等。 ASP.NET是在.NET下的网站开发技术。 安装.NET FrameWork就可以运行。VS集成安装了.NET FrameWork. 控制…

业务活动监视器(BAM)2.0带来的革命

生产兼具精益和企业价值的中间件是一项艰巨的工作。 它要么不存在&#xff0c;要么需要创新的思维&#xff08;很多&#xff09;&#xff0c;并且需要在实现中反复进行。 业务风险很大&#xff0c;但是如果您做对了&#xff0c;它就会使您领先于其他任何公司。 这就是为什么我们…

oracle销售服务器吗,oracle 服务器 版本

oracle 服务器 版本 内容精选换一换Atlas 800 训练服务器(型号 9010)安装上架、服务器基础参数配置、安装操作系统等操作请参见《Atlas 800 训练服务器 用户指南 (型号9010)》。Atlas 800 训练服务器(型号 9010)适配操作系统如表1所示。请参考表2下载驱动和固件包。Atlas 800 训…

Vue组件间通信:一个例子学会Vue组件-Vue.js学习总结)(转载)

详情请点击 http://www.jianshu.com/p/9ad1ba89a04b转载于:https://www.cnblogs.com/zhongjiang/p/6694459.html

必填字段的自定义JSF验证器

实现EditableValueHolder接口的JSF组件具有两个属性“ required”和“ requiredMessage” –一个标志&#xff0c;指示用户需要输入/选择非空值&#xff0c;以及一个用于验证消息的文本。 我们可以使用它&#xff0c;但是它不够灵活&#xff0c;我们不能直接在视图中&#xff0…

java 转码%2f%_JS和JAVA中常用的编码转码函数

js中escape,encodeURI,encodeURIComponent函数和unescape,decodeURI和decodeURIComponent函数的功能1.escape方法对String对象编码,escape方法返回一个包含了"转义序列"的字符串值。除了ASCII字母和数字&#xff0c;以及这几个符号 *-/._外(共有1052769个字符不会被编…

mybatis 下划线转驼峰配置

一直以来&#xff0c;在sqlmap文件中&#xff0c;对于数据库中的下划线字段转驼峰&#xff0c;我们都是通过resultmap来做的&#xff0c;如下&#xff1a; <resultMap id"ISTableStatistics" type"com.medsoft.perfstat.pojo.ISTableStatistics" > &…

Python练习-迭代器-模拟cat|grep文件

代码如下: 1 # 编辑者&#xff1a;闫龙2 def grep(FindWhat):3 fopen("a.txt","r",encoding"utf8")#以只读的方式打开a.txt文件4 while True:5 try:6 fline next(f).strip()#由于File类型本身就是一个迭代器,所以直…

Spring和JSF集成:转换器

使用任何Web框架时&#xff0c;都不可避免地需要将用户输入的数据从String为其他类型。 尽管Spring和JSF在设计和功能上确实有很大的不同&#xff0c;但它们都具有转换器策略来处理此问题。 让我们从春天开始。 Spring 3引入了一个全新的转换框架&#xff0c;该框架允许将任何类…

nacos配置ap_Nacos 1.0.0 功能预览

本文来自于我的个人主页&#xff1a;Nacos 1.0.0 功能预览&#xff0c;转载请保留链接 ;)Nacos 1.0.0 是正式 GA 的版本&#xff0c;在架构、功能和API设计上进行了全方位的重构和升级&#xff0c;1.0.0版本标志着Nacos的架构已经稳定&#xff0c;API列表最终确定。升级到1.0.0…

poj 2229 Sumsets

题目大意&#xff1a; 一个数由2的幂次数的和构成&#xff0c;问有几种构成方式&#xff1f; 主要是找规律 代码如下 1 #include <cstdio>2 #include <cstring>3 int n;4 #define M 10000000005 int dp[1000002];6 7 int main(int argc, char const *argv[])8 {9 …

html 甘特图_Rplotly|交互式甘特图(Gantt chart)项目管理/学习计划

甘特图(Gantt chart)&#xff0c;又常被称为横道图或者条状图&#xff0c;是现代企业项目管理领域运用最为广泛的一种图示。就是通过条形来显示项目的进度、时间安排等相关情况的。项目管理外&#xff0c;也可以用来管理学习计划。绘制甘特图的工具有很多&#xff0c;本文介绍使…

使您的Spring Security @Secured注释更干燥

最近&#xff0c;Grails用户邮件列表中的一个用户想知道在定义Secured批注时如何减少重复 。 在Java批注中指定属性的规则非常严格&#xff0c;因此我看不到直接执行他所要求的方法的方法。 使用Groovy并没有真正的帮助&#xff0c;因为Groovy类中的注释大部分与Java中的注释几…

阅读《大型网站技术架构》 第三章心得

今天阅读了《大型网站技术架构》 的第三章&#xff0c;这一章主要讲解了大型网站核心架构要素&#xff0c;并且概括的讲解了相应的实现方法。 软件架构除了系统功能需求外&#xff0c;还需要关注性能、可用性、伸缩性、扩展性、安全性。 其中性能是网站的重要指标。优化网站性能…

easyui数据表格重置_数据库三种删除方式

第一种 使用delete 语句特点&#xff1a;delete 属于数据库操纵语言DML&#xff0c;表示删除表中的数据&#xff0c;删除过程是每次从表中删除一行&#xff0c;并把该行删除操作作为事务记录在日志中保存可以配合事件&#xff08;transaction&#xff09;和 回滚&#xff08;ro…