α角 与 β角

支持 现实生活 的 计算机系统,总有着两大偏差,第一个是 现实生活计算机系统 的α角,另外一个是计算机系统的 逻辑设计物理设计 的β角。举个栗子:

  • α角:假设某个公司的商业流程,我们在做计算机自动化的时候,会发生某种程度的改变。可能是用了新计算机系统,需要调整商业流程;也可能是某些商业流程,由于种种原因,没有被计算机系统实现支持。。。
  • β角:这个比较常见,例如某个类本身是没有什么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的实现方法。
用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的更多相关文章

  1. EFCore Lazy Loading + Inheritance = 干净的数据表 (二) 【献给处女座的DB First程序猿】

    前言 本篇是上一篇EFCore Lazy Loading + Inheritance = 干净的数据表 (一) [献给处女座的DB First程序猿] 前菜 的续篇.这一篇才是真的为处女座的DB Fi ...

  2. EFCore Lazy Loading + Inheritance = 干净的数据表 (一) 【献给处女座的DB First程序猿】

    前言 α角 与 β角 关于α角 与 β角的介绍,请见上文 如何用EFCore Lazy Loading实现Entity Split. 本篇会继续有关于β角的彩蛋在等着大家去发掘./斜眼笑 其他 本篇的 ...

  3. Entity Framework加载相关实体——延迟加载Lazy Loading、贪婪加载Eager Loading、显示加载Explicit Loading

    Entity Framework提供了三种加载相关实体的方法:Lazy Loading,Eager Loading和Explicit Loading.首先我们先来看一下MSDN对三种加载实体方法的定义 ...

  4. Entity Framework Tutorial Basics(37):Lazy Loading

    Lazy Loading: One of the important functions of Entity Framework is lazy loading. Lazy loading means ...

  5. iOS swift lazy loading

    Why bother lazy loading and purging pages, you ask? Well, in this example, it won't matter too much ...

  6. Lazy<T>在Entity Framework中的性能优化实践

    Lazy<T>在Entity Framework中的性能优化实践(附源码) 2013-10-27 18:12 by JustRun, 328 阅读, 4 评论, 收藏, 编辑 在使用EF的 ...

  7. 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 ...

  8. WPF/SL: lazy loading TreeView

    Posted on January 25, 2012 by Matthieu MEZIL 01/26/2012: Code update Imagine the following scenario: ...

  9. 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制

    你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...

随机推荐

  1. topcoder srm 600 div1

    problem1 link 首先,如果一个数字的某一位是1但是$goal$的这一位不是1,那么这个数字是不用管它的.那么对于剩下的数字,只需要统计在$goal$为1的位上,这些数字对应位上也是1的数字 ...

  2. Bootstrap3基础 栅格系统 col-lg/md/sm/xs-* 简单示例

      内容 参数   OS   Windows 10 x64   browser   Firefox 65.0.2   framework     Bootstrap 3.3.7   editor    ...

  3. HTML解析之BeautifulSoup

    BeautifulSoup是一个用于从HTML和XML文件中提取数据的Python库.BeautifulSoup提供一些简单的.函数用来处理导航.搜索.修改分析树等功能.BeautifulSoup模块 ...

  4. git遇到error: RPC failed; curl 18 transfer closed with outstanding read data remaining fatal: The remote end hung up unexpectedly fatal: early EOF fatal: index-pack failed failed怎么办?

    答: 将clone地址中的https://替换成git://即可解决 如: 将https://git.openwrt.org/project/luci.git修改为git://git.openwrt. ...

  5. MpVue 致力打造H5与小程序的代码共用

    MpVue是什么 基于 Vue.js 的小程序开发框架 从底层支持 Vue.js 语法和构建工具体系. 使用vue开发小程序 修改了 Vue.js 的 runtime 和 compiler 实现,使其 ...

  6. 【HNOI 2018】转盘

    Problem Description 一次小 \(G\) 和小 \(H\) 原本准备去聚餐,但由于太麻烦了于是题面简化如下: 一个转盘上有摆成一圈的 \(n\) 个物品(编号 \(1\) 至 \(n ...

  7. three.js初探,立体几何入手(一)

    前言:首先先推荐一篇博客,关于webgl原理,讲的非常之通俗易懂了 图解WebGL&Three.js工作原理  webGL可以理解为openGL ES2.0 (webGL2.0 - openG ...

  8. 在 Laravel 项目中使用 Elasticsearch 做引擎,scout 全文搜索(小白出品, 绝对白话)

    项目中需要搜索, 所以从零开始学习大家都在用的搜索神器 elasiticsearch. 刚开始 google 的时候, 搜到好多经验贴和视频(中文的, 英文的), 但是由于是第一次接触, 一点概念都没 ...

  9. Hadoop之运行环境搭建

    一.虚拟机环境准备 1.克隆虚拟机 2.修改克隆虚拟机静态IP 3.修改主机名 4.关闭防火墙 5.创建hadoop用户 6.配置hadoop用户具有root权限 7.在/opt 目录下创建文件夹 1 ...

  10. 20175317 MyCP(课下作业,必做)

    一.题目要求 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bin 用来把文本文件(内 ...