概述
实体框架是一个 ORM
框架,它在结构和使用上参考了 Entity Framework
,lambda
表达式的解析部份参考了 iqtoolkit
和 NLite
开源框架。
Fireasy 实体框架与 Entity Framework
非常类似,都可以使用 lambdal
表达式查询,但在操作上却不大相同。Fireasy 实体框架比较快捷,它提供了 Insert、Update、Delete 等方法,而不需要像 Entity Framework
所有的对象都需要状态管控,所有改动都在最后使用 SaveChanage 方法进行提交。
另外,Fireasy 实体框架本身已经适配了多种数据库,如 SqlServer
、Oracle
、MySql
、SQLite
、PostgreSql
、Firebird
,MariaDB
(使用 MySql 适配),你只需在 Nuget 管理器 里安装相应数据库的驱动包就可以了,具体可参考 数据库提供者。
👆 主要特性
- 依赖属性:你所看不到的又不得不了解的东西,它的存在为为了能够及时通知属性值的变更,属性的赋值与取值都跟它息息相关。
- 实体属性及实体集属性:和
Entity Framework
里的导航属性是一个概念,目的是为了实现关联查询。 - 实体模型:
IEntity
定义了一组实体的特性,正如上面说的一样, GetValue 和 SetValue 离不开依赖属性,IsModified 可判断属性值是否改变。LightEntity
是目前所采用的基类,它在EntityContext
初始化时,自动进行了AOP
代理包装,使实体获得了状态记忆功能。因此你的属性需要定义成virtual
。 - 实体关系:与
Entity Framework
类似,用于定义实体间的关系,主外键名称一致的情况下会自动创建关系,否则需要使用RelationshipAttribute
或RelationshipAssignAttribute
关联。 - 实体上下文:提供类似于
Entity Framework
的数据上下文,即EntityContext
,它一样可以使用 CodeFirst 模式。 - 实体上下文对象池:可以使用对象池,提高对象的复用率降低创建对象耗用的时间。
- 实体仓储:每一个实体对应一个仓储,它们分布在
EntityContext
上,提供lambda
表达式查询、新增、修改、删除等提供。 - 仓储适配器:默认的适配器是基于 Fireasy.Data 的,你也可以实现其他的适配器,以达到在不改变Entity模型的情况下依然可以使用其他框架的目的,比如
Entity Framework
、Mongodb
等等。 - lambda 查询:支持常用的原生
lambda
查询,如 Where、OrderBy、GroupBy、Join 等等。 - 逻辑删除标记:实体设置逻辑删除标记后,查询时将自动过滤这些已经被标记的数据。
- 全局筛选:Apply 方法可以定义针对某实体类型的全局筛选条件。
- 延迟加载:对于关联属性,可以在需要的时候才从库中读取加载。
- 惰性加载:对于关联属性,由于延迟加载机制将发生 n+1 次数据库查询动作,此时可以使用Include方法将关联属性预先加载出来。
- 扩展方法:对
IQueryable
查询的扩展,比较常用的如 Segment、AssertWhere、ExtendAs、BatchOr、BatchAnd、CacheParsing 等等,具体的使用不在这里说明。 - 树结构:采用类似 00010001 的编码来管理树结构,提供插入、移动、枚举孩子、递归父亲、获取兄弟等方法。
- 数据验证:基于
DataAnnotations
制定实体的数据验证规则。 - 持久化事务:基于
Scope
定义线程内的事务控制。 - 持久化环境:根据环境内的参数,格式化实体所映射的表名称,实现数据表横向扩展。
- 持久化事件订阅:提供一个订阅器,用于接收持久化事件,如新增、修改、删除等,事件分为 Before 和 After,Before 还可以对该操作进行取消。
- 动态持久化:通过动态构造实体类型,实现其持久化操作。
- 解析缓存:
lambda
表达式解析时,可以通过配置开启自动缓存开关(默认开),开启后,LINQ的解析时间将会有效缩短,该缓存存放于内存中,部分LINQ解析缓存存在问题,可在查询中使用CacheParsing关闭。 - 查询缓存:查询返回数据时,可以通过配置开启自动缓存开关(默认关),缓存是由
Fireasy.Common
缓存管理器提供的(最好是配置redis)。也可以在查询中使用 CacheExecution 指定是否开启查询缓存。 - 自定义函数:可在查询中使用自定义方法,该方法与数据库的自定义函数相对应。
- 方法绑定:可在查询中自定义方法,对该方法进行绑定,即转换为可解析的
lambda
表达式。
👆 结构图
下面是本章中比较重要的几个接口和类的结构图:
👆 示例代码
public void Sample()
{
using (var context = new DbContext())
{
DateTime? startTime = null;
DateTime? endTime = null;
var state = 0;
//AssertWhere 用法
var orders = context.Orders
.AssertWhere(startTime != null, s => s.OrderDate >= startTime)
.AssertWhere(endTime != null, s => s.OrderDate <= endTime)
.AssertWhere(state == 0, s => s.RequiredDate == DateTime.Now, s => s.RequiredDate >= DateTime.Now)
.AsNoTracking();
//ExtandAs 扩展用法
var details = context.OrderDetails.Select(s =>
s.ExtendAs<OrderDetails>(() => new OrderDetails
{
ProductName = s.Products.ProductName
}))
.ToList();
//分页
var pager = new DataPager(50, 2);
var products = context.Products.Segment(pager).ToList();
//排序
var sorting = new SortDefinition();
sorting.Member = "OrderDate";
sorting.Order = SortOrder.Descending;
var orders1 = context.Orders
.Select(s => new { s.OrderDate, CompanyName = s.Customers.CompanyName })
.OrderBy(sorting, u => u.OrderByDescending(s => s.OrderDate))
.ToList();
//按条件更新
context.Orders.Update(() => new Orders { Freight = 1 }, s => s.OrderDate >= DateTime.Now);
//计算器方式更新
context.Orders.Update(s => new Orders { Freight = s.Freight * 100 }, s => s.OrderDate >= DateTime.Now);
//按条件删除
context.Orders.Delete(s => s.OrderDate > DateTime.Now);
//Batch插入
var depts = new List<Depts>();
for (var i = 0; i < 100; i++)
{
var d = Depts.New();
d.DeptName = "测试" + i;
depts.Add(d);
}
context.Depts.Batch(depts, (u, s) => u.Insert(s));
}
}