从EF的使用中探讨业务模型能否脱离单一存储层完全抽象存在
上次赶时间,就很流水账地写了上次项目对EF的一次实践应用模式,因为太长了,也没能探讨太多,所以再继续扩展。
这次想探讨的是,实体,如果作为类似于领域模型的业务模型存在,它的数据能否来自不同的数据源。这个想法首先是来自于这次应用中,Model First + 代码补充的方式形成了一个极好的效果。一方面满足了范式,减少了数据存储量;另一方面利用了封装特性,向业务提供了一个符合业务期望的实体。
首先看一个例子
我用Model First建立了Account一个实体,实际生成的代码如下:
public partial class Account
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
对应地,上面三个字段分别对应着数据库中的三个字段。
然后,我再用Partial Class的方式,为Account进行扩充:
public partial class Account
{
public string FullName
{
get
{
if (this._fullName == null)
{
this._fullName = String.Format("{0} {1}", this.FirstName, this.LastName);
}
return this._fullName;
}
} string _fullName;
}
这里就是关键了。此时,业务逻辑拿到的称之为Account的就不再是简单的DAO对象了,而是一个有着四个业务所需字段的业务模型对象。有兴趣的可以去看看我上一篇《Entity Framework 与 面向对象》中间设计模式的部分,里面讲到了为实体应用上了继承、多态、封装等面向对象的设计方式以达到业务模型所需的效果。
我的问题
这种为Entity添加完整面向对象特性的方式,有着一种想法,那就是能否让一个Entity完全抽象架空于存储层,允许一个Entity的数据来自不同的数据源。
首先,如果在存储层的视角来看,示例中Account的三个字段Id、FirstName、LastName来自于关系数据库,而FullName来自于计算值,也就是内存。站在数据库的角度上来说,FullName确实是不符合范式,所以很“多余”。
如果从时间线来说,在实例化的时候,前三个数据库字段的数据就已经被加载了,而FullName是Lazy Load。
但是,对于业务来说,他获得的不过是一个包含四个字段的Account的实例。
那么我的问题就继续扩展了,一个业务模型,能不能将数据源完全封装,在业务获得该实体的时候,完全脱离关注实现?
当我获得一个产品,那么这个产品的基本属性来自关系数据库,产品介绍来自NoSql,统计值来自动态计算。重要的是,这要是一个对象,而不是自行用多个对象拼装出来的。
实际上,是封装的问题
实际上,来到这里,就已经很明朗,这是一个封装的问题。我们从前遇到的是关系数据库和面向对象的阻抗失配,然后用ORM解决了。而今天,我们还可能遇到非强类型对象和非关系数据库以及强类型对象和关系数据库混合使用的问题,而且这使得其成为常态。
通常,因为一个特性的原因,我们要在技术上进行选型。要么用静态语言,要么用动态语言。但是当出现一个用另一种方式更合适的时候,实现就变得很别扭了。
比如用上面产品的问题,多少人是把产品详情作为整个文本值存在一个字段里呢?多少人又在用一张表来解决动态字段的问题呢?
实现,现实吗
在Account的例子中,这种行为很容易实现。一方面依托于EF提供了相关的支持,另一方面是两个存储源具有时间上的关联。在进行一项业务的时候,所有数据库里,也就是存储在持久化存储器内的数据,最终都要读取到内存中才能被操作。这种纵向的关系,方面了应该来自于内存的数据源在产生数据的行为嵌入到整个业务过程中。
但是当两个数据源没有纵向关系而是平行关系的时候,问题就来了。这个状况就跟当年的阻抗失配的问题类似。
首先是一个迭代的问题。
大家都知道,获取数据是有获取成本的。数据在抽象层面是“获取”,在实现层面是一次“拷贝”,拷贝的过程包括了“传输”。拷贝和传输就是数据获取的成本,这个成本在一些情形可以被很大的放大,比如从前的递归查询。
如果不把递归写成SQL,那么在业务层面进行解决的话,就要往返很多次数据库获取数据。产生的业务结果是一样的,但产生的性能结果差异极大。
而我假象的获取数据的行为是这样的:
可以简单当两个数据源的时候,会存在一个“数据汇合”的问题,其实就是一个同步和匹配问题。
两个数据源获取到的数据需要匹配上,在一个大量查询的时候就变得很麻烦了。如果按照顺序进行匹配不就简单了?但是要知道,“顺序”是个很奇怪的命题,你查找到的数据是一个集合或者列表才有“顺序”,对于NoSQL一类Key-Value的形态,如何定义顺序呢?
另外,如果是要一个数据源强行配合另一个数据源,那么一次数据获取行为的效率,就是由最慢的一个数据源决定的。
我再是想一下,如果是全部或者部分延迟加载,那么是不是说,读取数据都需要是异步的,而且合并数据的情况下,需要有一个用以合并数据的线程。
我打算尝试
实际会遇到什么情况不好说,所以我倒是乐于去尝试一下。
一开始的思路,是先尝试继续用扩充字段,然后把数据源获取封装好;然后我应该尝试去切入LinQ Provider,看看能不能在LinQ中下手,这对于.NET的使用或许更重要。
从EF的使用中探讨业务模型能否脱离单一存储层完全抽象存在的更多相关文章
- EF Core中避免贫血模型的三种行之有效的方法(翻译)
Paul Hiles: 3 ways to avoid an anemic domain model in EF Core 1.引言 在使用ORM中(比如Entity Framework)贫血领域模型 ...
- 分析业务模型-类图(Class Diagram)
分析业务模型-类图(Class Diagram) 分析业务模型-类图(Class Diagram)(上) 摘要:类图(Class Diagram)可能是用得最多的一种UML图.类图的基本语法并 ...
- BIEE入门(三)业务模型层
正如它的名字所示(Business Model and Mapping Layer),业务逻辑层需要把物理层的数据源以一种业务用户的视角来重新组织物理层的各个数据源(所谓的Mapping),同时在业务 ...
- How to: Create a Business Model in the XPO Data Model Designer 如何:在 XPO 数据模型设计器中创建业务模型
This topic provides step-by-step instructions on how to use the XPO Data Model Designer in XAF appli ...
- 电商架构设计-通过系统和业务拆分,遵循单一职责原则SRP,保障整个系统的可用性和稳定性
个人观察 1.通过系统和业务拆分,遵循单一职责原则SRP,保障整个系统的可用性和稳定性. 2.单一职责原则SRP,真的很关键,广大程序员需要不断深入理解这个原则. 3.架构图是架构师的重要输出,通过图 ...
- JVM并发机制的探讨——内存模型、内存可见性和指令重排序
并发本来就是个有意思的问题,尤其是现在又流行这么一句话:“高帅富加机器,穷矮搓搞优化”. 从这句话可以看到,无论是高帅富还是穷矮搓都需要深入理解并发编程,高帅富加多了机器,需要协调多台机器或者多个CP ...
- 使用EF Model First创建edmx模型,数据库有数据的情况下,如何同时更新模型和数据库
使用"EF Model First",我们可以很直观地在edmx文件中创建数据模型,并根据模型生成数据库,整个过程快速而高效.可当数据库中有了一定的数据量,同时,可能需要对模型中字 ...
- ASP.NET Core 使用 SQLite 教程,EF SQLite教程,修改模型更新数据库,适合初学者看懂详细、简单教程
SQLIte 操作方便,简单小巧,这里笔者就不再过多介绍,感兴趣可以到以下博文 https://blog.csdn.net/qq_31930499/article/details/80420246 文 ...
- BW ON HANA 业务模型关系与数据取数
在接到业务需求之后,我认为重要的是理清楚自己该做什么.来实现业务.由于不了解业务,还是走了很多弯路.本可以不用这么做,还是这么做了.自然你最傻瓜的按照用户的方式去实现是没有问题的. 会使后面的人难以维 ...
随机推荐
- JS核心系列:浅谈原型对象和原型链
在Javascript中,万物皆对象,但对象也有区别,大致可以分为两类,即:普通对象(Object)和函数对象(Function). 一般而言,通过new Function产生的对象是函数对象,其他对 ...
- 如何优雅的使用RabbitMQ
RabbitMQ无疑是目前最流行的消息队列之一,对各种语言环境的支持也很丰富,作为一个.NET developer有必要学习和了解这一工具.消息队列的使用场景大概有3种: 1.系统集成,分布式系统的设 ...
- 实例操作JSONP原理
絮语:按这个步骤走,你就会明白JSONP是什么鬼. 1.工程目录: ng-mywork demo.html test.js 2.nginx的server配置 server { listen ; ser ...
- js学习之类型识别
用来判别类型的方法有好多,整理了一下4种方法,平时用的时候,在不同情景下,还是要结合着使用的. 方法一 typeof:可以识别标准类型,除了Null:不能识别具体的对象类型,除了Function &l ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- C++整数转字符串的一种方法
#include <sstream> //ostringstream, ostringstream::str() ostringstream stream; stream << ...
- Maven常用命令
开发中常用的命令: 1. mvn compile 编译源代码2. mvn test-compile 编译测试代码3. mvn test 运行测试4. mvn package 打包,根据pom.xml打 ...
- NOIP2016纪录[那些我所追求的]
人生第一场正式OI [序] 2016-12-04 见底部 [Day -1] 2016-11-17 期中考试无心插柳柳成荫,考了全市第2班里第1(还不是因为只复习了不到两天考试),马上请了一个周的假准备 ...
- Unity插件之plyGame教程:DiaQ对话系统
本文为孤月蓝风编写,转载请注明出处:http://fengyu.name/?cat=game&id=296 DiaQ是plyGame旗下的一款对话及任务系统.拥有可视化的对话及任务编辑器,能够 ...
- HTML5- Canvas入门(五)
今天要介绍的是canvas对图形对象的操作,包括图像.视频绘制,和操作像素对象的方法. 图片/视频的绘制 在canvas中,我们可以通过 drawImage() 的方法来绘制图片或视频文件,其语法为: ...