EntityModel 一个简单而实用的ORM构架

EntityModel是用C#实现的一个简单实用的ORM构架,同时支持.Net Framework与 dotnet Core。支持Mysql\Sql Server\Sqlite数据库,通过设计工具的配合,无论简单的增删改查还是复杂的级联数据,都可轻松搞定。本文对EntityModel的特性做一个简单介绍,后续会以Step by step的形式介绍如何正确的掌握它。
项目地址:https://github.com/agebullhu/EntityModel
工具地址:https://github.com/agebullhu/AgebullDesigner

1. 简单封装与代码生成
我们需要的很多常用功能,如果需要手工编码,工作量非常繁重,从而导致生产效率低下或无法实行。常用解决方案有两种,第一种是进行全面的封装,第二种是使用代码生成器支持。由于数据的多样性,很难做到大一统的良好封装,所以我们另辟蹊径,只进行简单的封装,将复杂性通过海量代码来解决。同时,也可以避免封装带来的黑盒困惑(使用者不知道后面的具体如何实现,往往通过猜测来判断问题)。
2. 实体
2.1.    常用功能的支持
2.1.1.    属性变更跟踪
数据逻辑是复杂的,但很多业务模型中,属性带来的流程处理或变更是极其复杂的。

一个典型的例子就是在MVVM模型中,属性的变化,必须通知UI模型,在一系列的内部处理最终呈现在界面上,并且还需要防止事件重发(界面更新事件触发反向再更改到属性而引发的死循环)。

在我们的设计中,参考了WPF的MVVM模型,所有的Entity类的基类为NotificationObject,通过PropertyChanged事件简化属性变更的复杂性。基于发布订阅模式,实体只需要发出事件(event)即可,不做任务处理,实现解耦。
为了方便订阅集合的事件,我们也扩展了ObservableCollection类,通过ObjectCollection可自动转发属性变更事件。
2.1.2.    深拷贝与匿名属性操作

匿名属性操作
在无法确定对象类型的场景下(比如在基类或依赖类中),C#通过属性进行操作的是无法做到的,我们通过文本名称实现类似Get或Set的操作,从而绕过C#语言障碍。这种方式我们称为匿名属性操作。
数据复制与与匿名属性操作
这是一个常用的能力,所以我们将之纳入我们的基础支持中。通过实现IDataObject接口实现对应功能,通过CopyValue方法实现深拷贝,通过GetValue、SetValue两个方法实现匿名赋值与取值。

2.1.3.    数据状态跟踪
在多数情况,我们需要对数据状态进行判断,以确定是否进行对应的操作,从而解除对操作前置条件的依赖。

很典型的一个例子是,在数据保存操作之前,我们要确定数据是否修改,如果未修改,就不应该进行数据库更新操作,如果已修改,在开放场景下(即未防止并发写入)仅应该写入已修改的内容,以降低并发风险。

在早期的EntityFramework中(说实话版本4之后我就没用过它了 ),数据状态保持是在线的(即在内存中保持),这极大限制了应用场景,所以我们通过扩展属性**__EntityStatus**来实现离线状态保持。属性内部记录已修改的属性序号,实体状态(是否存在、是否删除)。为了保持数据的干净,我们通过__IsReadOnly扩展属性对只读数据限制__EntityStatus的实例能否存在。

扩展属性我们都用双下划线前缀来防止属性名称冲突

2.1.4.    存储无关性与存储支持
实体设计,不应该与数据存储方式有任何的绑定,是互相独立的,DataSet的失败就是一个反例。但在许多场景下,为了解除这种绑定,会导致逻辑极度复杂。基于这两个理由,我们设计了很多的扩展方法,提供给存储实现对象进行调用(反向解耦)。
如属性修改前后的partial方法,保存前后期处理的partial方法。这些方法,通过代码生成器进行支持。数据存储对象通过调用LaterPeriodByModify方法,获得实体数据规整的能力。
2.1.5.    数据校验支持
数据检验,是数据完整性的一个保证,所有数据在应用之前,都应该进行校验。所以我们的实体默认支持数据校验的功能,由于数据校验的复杂性,我们通过代码生成器的设计功能进行配置,通过代码生成器来简化封装难度。
2.1.6.    数据结构支持
数据结构支持,可以提供很多功能的扩展,比如说数据导入导出。我们在代码生成器设计的基础上,生成数据结构描述(即对EntitySturct __Struct属性的实现),对需要基于数据结构的扩展组件提供基础支持。
2.1.7.    跨应用域支持
我们的数据,需要在不同场景处理,需要在网络中传输,在这些过程中,数据特性将丢失殆尽。所以我们对数据特性的支持应可以进行还原,这些能力,我们也是通过代码生成器进行支持,即反序列化来自网络的数据时,通过数据比对,收集真实的数据修改状态。同时,我们还标明数据的来源。通过这些跨应用域支持,保证以上功能可正常使用。
2.2.    数据多样性的基础支持(多态)
2.2.1.    数据状态(IStateData)
数据状态,从逻辑删除开始,我们总是不断发现新的需求。为了应对这些需求,我们参考了OA系统的设计,对数据状态进行了扩展,以提供更好的扩展性。

数据锁定:
这个需求是独立的,任何情况都可能发生。所以我们通过IsFreeze属性来进行更新的低层条件,以减少失误。
数据状态:
这是一组互斥的数据状态(非业务状态,但对业务状态提供数据抽象层面上的支持),通过DataState属性支持(对应数据库中的data_state字段),有:草稿、启用、禁用、废弃(可见)、删除(不可见)等状态,并可进行更多的扩展。

2.2.2.    主键(IIdentityData)
这和数据库的主键是相同的,并进行映射。我们规定,主键为Int64类型。
2.2.3.    标题(ITitle)
很多时候,我们的实体都有一个字段充当了标题的能力, 比如字典数据中的标题,个人信息中的姓名,可以标明实体的主要含义。而这个应用场景很常见,比如数据将出现在下拉列表中,出现在字典对象中。在这些场景中,我们可以通过检测是否实现此接口,批量提供这些场景的支持,直接通过代码生成器实现,简化开发工作。
2.2.4.    作者与修改信息日志(IHistory)
这也是一个很常见的数据库设计方式,以保证数据可溯源这个需求。
3. 数据存储
3.1.    指导思想

多数据库支持,常见的数据库都应该提供相同的支持。
支持Lambda表达式
原始Sql语句操作
常用方法的支持
高级功能透明实现
快速开发与深度优化
单表操作
轻数据库重代码

3.2.    通用功能

数据读取
数据写入
单字段操作
数据自动同步
基础条件锁定

3.3.    数据变更事件
在数据写入数据库后,数据已实际变更,对于缓存需求,应最快的时行同步,所以我们增加了数据变更事件,以支持这个需求。
3.4.    EF兼容性
我们不支持Linq语法糖,重要的原因是:Linq解析消耗性能,并且优化极其困难。但为了快速开发,我们对查询条件提供Lambda表达式的解析支持。
3.5.    快速开发与深度优化
多数项目总是要求越快越好,所以我们支持快速开发,通过代码生成器完成所有基础代码.并建议开发初期查询条件使用Lambda表达式。
项目上线后,优化是必须的.所以我们提供与Lambda表达式对应的方法,进行纯SQL的优化与改造
3.6.    数据库魔法
3.6.1.    动态换表
我们通过ReadTableScope对象,可在范围中透明修改当前读取的表名,避免为了一次读取建立一套相同模型的麻烦
3.6.2.    基础条件封锁
数据在不同身份的用户场景下,因用户身份或类似原因需要限制访问范围,是很常见的需求.所以我们通过基础条件注入来原始支持这个功能并代替原来用视图或存储过程的复杂实现.

此封锁是在数据访问前进行的条件注入,所以可以保证不发生此类BUG.

3.6.3.    数据入侵
数据在设计上,总是有一些基础需求的,例如数据的修改者记录,正常我们进行的处理都是在每一处保存时写入这个值,由于业务的特殊性,这会出现在很多地方,容易因人的原因疏忽,所以我们通过数据入侵的方式,在写入前更改数据,从而保证数据完整性.
3.6.4.    数据差异透明
数据在数据库中与代码中,因语言或设计思想上的不同,数据差异性必然存在,常见的有:

字段名称差异:在C#中,我们希望属性名称为大驼峰,在Mysql中习惯的方式为小写下划线组合,我们通过字段映射表来支持这种差异化.
字段数量差异:比如说数据特性字段,在有些场景中并不需要,仅作为数据库中的查询条件存在,那我们就不读入实体中,反之,有些字段是数据库中没有的,我们也很智能的跳过它。通过设计器与基本封装支持这种差异化
数据格式差异:比如说枚举,我们在数据库中通常设计为整数,而我们在代码中使用枚举能更清晰表达,我们在数据转换时透明支持这种转换
数据操作差异:比如删除,物理删除与逻辑删除的SQL是不一样的,我样通过Delete基础SQL拼接来透明化这种差异
数据规则差异:最常见的差异是字段是否为空的差异,很多时间,我们应该允许不完全数据写入数据库,但在使用数据时必须是完整的,所以我们在数据库中为空的字段,可能在实体中为非空类型,空值读入时,我们通过默认值(如数字默认为0)填充,并在数据使用时遵循这个原则。

转载:https://blog.csdn.net/longhutian/article/details/88089657
 

猜你喜欢

转载自blog.csdn.net/qq_28368039/article/details/88109537
今日推荐