如何用EFCore Lazy Loading实现Entity Split
α角 与 β角
支持 现实生活 的 计算机系统,总有着两大偏差,第一个是 现实生活 与 计算机系统 的α角,另外一个是计算机系统的 逻辑设计 与 物理设计 的β角。举个栗子:
- α角:假设某个公司的商业流程,我们在做计算机自动化的时候,会发生某种程度的改变。可能是用了新计算机系统,需要调整商业流程;也可能是某些商业流程,由于种种原因,没有被计算机系统实现支持。。。
- β角:这个比较常见,例如某个类本身是没有什么ID之类的属性,而由于我们选择了某个数据库产品来做持久化,而数据表的主键用了 某某ID 这样的字段,于是引致我们的 类 里面也可能会包含了 ID 这样的属性;或者由于需要用 SQL Server 的 数据复制 功能,从而使到我们的类加入了各种TimeStamp字段
Entity Split
今天我们讨论的Entity Split,就是属于上述的β角。有时候,由于某些原因(例如 纵向切割 数据表),某个 类 ,它被保存到超过一个的数据表中。例如,我们可能有一个 Customer 类,由于它的属性比较多,于是为了提供系统性能,我们把最常用的属性归纳到 Customers 数据表,而把那些比较少用到的属性归纳到 CustomerOtherInfo 数据表,等等。
在用EF Core的时候,我们会在DbContext.OnModelCreating方法里面用modelBuilder.Entity<MyEntity>().ToTable("Tablename");的做法来指定 BusinessEntity 与 数据表 的映射关系,但是这个只能是Entity级别的,而没有能去到 属性 级别啊 。如何才能做得到指定 “某Entity的某些属性,映射到数据表A;而某些其他属性,映射到数据表B”,这样的效果呢?
(本篇的程序,可以在 https://github.com/kentliu2007/EFCoreDemo/tree/master/EntitySplit 上下载,我用的是 VS2017。建议可以下载之后,对照着程序来阅读本篇)
数据表
先来看看数据表是怎样的:

- Clients 表的索引


- ClientContactInfo 表的索引

- 外键FK_ClientContactInfo_Clients的设置

如何用EF5/6实现 Entity Split
首先让我们先来看看 EF5/6 是怎么实现的。
如果用EF5/6的话,这个很简单。因为有设计器啊,TableMapping就可以轻松搞定。
- 项目文件:

- EF Diagram:

- UnitTest程序:

看,程序完全不需要考虑数据是来源于不同的两个数据表。简单吧?
如何用EFCore 实现 Entity Split
用EF Core,没有设计器,怎么搞?其实,就算有设计器,也不能和EF5/6那样的实现方式的。
这里我们需要先请出 EF Core的一个重大功能 Lazy Loading。这个功能从EF Core V2 开始支持。
EF Core Lazy Loading
- 文档:https://docs.microsoft.com/zh-cn/ef/core/querying/related-data#lazy-loading
- 它有两种实现方式,
- 一种是用Microsoft.EntityFrameworkCore.Proxies包,以及调用UseLazyLoadingProxies来启用这个包。并且要求类里面的NavigationProperty需要是public且virtual
- 另外一种使用 Microsoft.EntityFrameworkCore.Abstractions 包中定义的 ILazyLoader 服务的引用。这个需要类里面做更多的特定代码来支持
上述两种做法各有利弊,所以我们接下来会针对两个做法都分别用一次。用它们来实现 基于 EF Core的Entity Split
可行性分析
通过上面分析的EFCore里面ToTable的做法,我们知道,实际上是真的不可避免地需要有俩 Entity ,这样才可以设置它们分别映射到不同的数据表。然后,因为有了Lazy Loading,我们可以对 Client 这个 主类 ,添加引用 ClientContactInfo 类的相应的几个属性。通过玩弄getter和setter的把戏。让EFCore的Lazy Loading在getter/setter调用到ClientContactInfo的属性的时候,按需装载,这样又可以实现Entity Split,系统性能也得到好处。
用Microsoft.EntityFrameworkCore.Proxies来实现EFCore的Entity Split
- 项目文件:

- 程序:
- DbContext:

- ClientContactInfo:

- Client:

- UnitTest:

看上面UnitTest的程序,就看出来,我们程序调用Client的时候,完全不需要考虑数据是来源于不同的两个数据表。Entity Split就这样搞定了。
用Microsoft.EntityFrameworkCore.Proxies的缺点是,我们需要有Client.ClientContactInfo这个NavigationProperty。而且还有另外一个可能的坑(如果你尝试调用Client.ClientContactInfo.GetType()就知道了,这个我们可以以后再特别弄个随笔来吐槽一下)。
接下来,为了维持OOP的美式咖啡口味,让我们换个Lazy Loading的实现方法。
- DbContext:
用Microsoft.EntityFrameworkCore.Abstractions来实现EFCore的Entity Split
- 项目文件:

- 程序:
- DbContext (这个和上面那个例子一样,就不骗篇幅了,大家继续参照上面那个Lazy Loading做法的贴图就好)
- ClientContactInfo(这个和上面那个例子一样,就不骗篇幅了,大家继续参照上面那个Lazy Loading做法的贴图就好)
- PocoLoadingExtensions (这个是直接抄微软文档上的,所以我也不骗篇幅,大家直接参阅上述微软文档的内容就好。网页上查找一下PocoLoadingExtensions这个文本就能找到了)
- Client:

程序里面用了一个private field来存放 ClientContactInfo的 实例,然后用了一个private的ClientContactInfo的property(通过继续玩弄它的getter/setter的把戏来帮忙提高程序的可维护性) - UnitTest(这个和上面那个例子一样,就不骗篇幅了,大家继续参照上面那个Lazy Loading做法的贴图就好)
用Microsoft.EntityFrameworkCore.Abstractions的缺点是,我们的类里面需要加入一些额外的程序(为了支持ILazyLoader )。但是好处是,Client的public属性里面,再也没有ClientContactInfo这种NavigationProperty了。就真的是毫无痕迹地实现了Entity Split。
结语
怎么样?EF Core真的很棒,对吧?借助Lazy Loading的功能,我们花费了一些周折,如此简单地实现了Entity Split。
当然,我本人还是希望Entity Split这个可以built-in为EF Core的一个基本功能,而不是采取借助Lazy Loading这样的Walk Around做法。也许接下来的第N个版本,它就会实现的。毕竟"面包会有的,牛奶会有的,一切都会有的。" :-P
下一篇,让我们继续讨论,如何借助Lazy Loading,在用EF Core的Inheritance功能的时候,继续保持数据表的清洁(不需要有冗余的字段)。敬请期待噢。 :-D
如何用EFCore Lazy Loading实现Entity Split的更多相关文章
- EFCore Lazy Loading + Inheritance = 干净的数据表 (二) 【献给处女座的DB First程序猿】
前言 本篇是上一篇EFCore Lazy Loading + Inheritance = 干净的数据表 (一) [献给处女座的DB First程序猿] 前菜 的续篇.这一篇才是真的为处女座的DB Fi ...
- EFCore Lazy Loading + Inheritance = 干净的数据表 (一) 【献给处女座的DB First程序猿】
前言 α角 与 β角 关于α角 与 β角的介绍,请见上文 如何用EFCore Lazy Loading实现Entity Split. 本篇会继续有关于β角的彩蛋在等着大家去发掘./斜眼笑 其他 本篇的 ...
- Entity Framework加载相关实体——延迟加载Lazy Loading、贪婪加载Eager Loading、显示加载Explicit Loading
Entity Framework提供了三种加载相关实体的方法:Lazy Loading,Eager Loading和Explicit Loading.首先我们先来看一下MSDN对三种加载实体方法的定义 ...
- Entity Framework Tutorial Basics(37):Lazy Loading
Lazy Loading: One of the important functions of Entity Framework is lazy loading. Lazy loading means ...
- iOS swift lazy loading
Why bother lazy loading and purging pages, you ask? Well, in this example, it won't matter too much ...
- Lazy<T>在Entity Framework中的性能优化实践
Lazy<T>在Entity Framework中的性能优化实践(附源码) 2013-10-27 18:12 by JustRun, 328 阅读, 4 评论, 收藏, 编辑 在使用EF的 ...
- Lazy Loading | Explicit Loading | Eager Loading in EntityFramework and EntityFramework.Core
EntityFramework Eagerly Loading Eager loading is the process whereby a query for one type of entity ...
- WPF/SL: lazy loading TreeView
Posted on January 25, 2012 by Matthieu MEZIL 01/26/2012: Code update Imagine the following scenario: ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
随机推荐
- UVA - 12298 Super Poker II NTT
UVA - 12298 Super Poker II NTT 链接 Vjudge 思路 暴力开个桶,然后统计,不过会T,用ntt或者fft,ntt用个大模数就行了,百度搜索"NTT大模数&q ...
- bzoj2194 快速傅立叶之二 ntt
bzoj2194 快速傅立叶之二 链接 bzoj 思路 对我这种和式不强的人,直接转二维看. 发现对\(C_k\)贡献的数对(i,j),都是右斜对角线. 既然贡献是对角线,我们可以利用对角线的性质了. ...
- 【新特性】JDK1.6
一.Desktop类和SystemTray类 在JDK6中 ,AWT新增加了两个类:Desktop和SystemTray. 前者可以用来打开系统默认浏览器浏览指定的URL,打开系统默认邮件客户端给指定 ...
- MapReduce实现PageRank算法(稀疏图法)
前言 本文用Python编写代码,并通过hadoop streaming框架运行. 算法思想 下图是一个网络: 考虑转移矩阵是一个很多的稀疏矩阵,我们可以用稀疏矩阵的形式表示,我们把web图中的每一个 ...
- GIT导出差异版本更新的文件列表
之前写了一篇SVN导出差异版本更新的文件列表 这次写git如何导出差异化版本文件列表 查找了一番,发现git diff这个命令 $ git diff 2da595c daea1d6 --name-on ...
- Git复习步骤
1.首先肯定是安装与配置了 首先要下载Git,然后设置用户名/邮箱 https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c ...
- Python开发 基础篇
2019-02-01 产生验证码: 用户输入的值和显示的值相同时显示Correct,否则继续生成随机验证码等待用户输入 def check_code(): import random checkcod ...
- 使用shiro的密码服务模块
http://jinnianshilongnian.iteye.com/blog/2021439 http://www.cnblogs.com/snidget/p/3817763.html
- vue-quill-editor富文本编辑器,上传图片自定义为借口上传
vue-quill-editor富文本编辑器,上传图片自定义为借口上传 博客地址:https://blog.csdn.net/lyj2018gyq/article/details/82585194
- PHP的openssl_encrypt方法的Java实现
<?php class OpenSSL3DES { /*密钥,22个字符*/ const KEY='09bd821d3e764f44899a9dc6'; /*向量,8个或10个字符*/ cons ...