两个星期前,微软发布了EF Core 2.1 Preview 1,同时还发布了.NET Core 2.1 Preview 1和ASP.NET Core 2.1 Preview 1;EF Core 2.1 Preview 1 除了许多小改进和超过100种产品错误修复之外,还包括几个常用的新功能,今天我为您详细介绍这些新功能的部分内容。
实体构造函数参数EF.Core 2.1开始支持在实体的构造函数的实体中转入参数,目前支持的类型如下:
实体属性
IOC容器中注册的服务
当前的DbContext
当前实体的元数据
实体属性在某些情况下为了保证数据的安全性,将属性改为只读,在构造函数中传递属性的值,框架通过参数与属性匹配关系,将数据行中属性的值作为参数传递给构造函数。
例如下面的实体:
public class Order { public Order(int orderID, string customerID, DateTime? orderDate) { OrderID = orderID; CustomerID = customerID; OrderDate = orderDate; } public int OrderID { get; } public string CustomerID { get; } public DateTime? OrderDate { get; } }其中参数与属性的配置规则如下:
参数的类型与属性的类型一致;
属性名与参数名除首字母不区分大小写之外,其它字符一致,并且可以使用 _ 、m_做为前缀,使用OrderID属性来举例,存在如下匹配规则:
OrderID OrderID
OrderID orderID
_OrderID orderID
_OrderID OrderID
m_OrderID OrderID
m_OrderID OrderID
具体的匹配规则可以见Github上面的源代码:
不过我认识后面四种模式有待斟酌的,在.Net开发规范,应该没有人将公有的属性名使用 _、m_作为前缀。
在实体的构造函数的中,可以将注册的服务作为参数。
示例代码:
public class Order { private ILazyLoader _lazyLoader; public Order(ILazyLoader lazyLoader) { this._lazyLoader = lazyLoader; } public int OrderID { get; set; } public string CustomerID { get; set; } private ICollection<OrderDetail> _orderDetails; public ICollection<OrderDetail> OrderDetails { get => _lazyLoader.Load(this, ref _orderDetails); set => _orderDetails = value; } } }其中ILazyLoader是EF Core框架在容器中注册的一个服务,通过实体的构造函数中传入,实现导航属性的赖加载(关于ILazyLoader的具体使用方式在本章的下一节中讲解)。
当前的DbContext在实体的构造函数的参数中,将当前的DbContext作为参数。
示例代码:
public class Order { private NorthwindContext _northwindContext; public Order(NorthwindContext northwindContext) { this._northwindContext = northwindContext; } public int OrderID { get; set; } public string CustomerID { get; set; } private ICollection<OrderDetail> _orderDetails; [NotMapped] public ICollection<OrderDetail> OrderDetails { get { if (this._orderDetails == null) this._orderDetails = this._northwindContext.Set<OrderDetail>() .Where(item => item.OrderID == this.OrderID).ToList(); return this._orderDetails; } set => _orderDetails = value; } } 当前实体的元数据在实体的构造函数的参数中,将当前实体的的IEntityType作为参数。
示例代码:
public class Order { private IEntityType _entityType; public Order(IEntityType entityType) { this._entityType = entityType; } public int OrderID { get; set; } public string CustomerID { get; set; } [NotMapped] public IEntityType EntityType { get { return this._entityType; } } }如果实体存在多个构造函数,框架会选择参数个数最多的那个;如果按参数个数优先选择后,依然存在多个构造函数,则会抛异常。在当前体验版本中,暂时无法直接支持自定义参数,不过在下一个发布版本中,会提供解决方案。
懒加载懒加载是一个非常有争论的功能激烈争论的功能。虽然有些人认为它会导致性能下降或出现意想不到的Bug,但是不影响有些开发人员依旧喜欢它。EF Core 2.1 Preview 1增加了懒加载,提供了两种实现方式。
使用ILazyLoader接口实现懒加载在实体的构造函数中传入ILazyLoader,在导航属性中,使用接口的Load方法,实现导航属性的数据加载。
示例代码:
public class Order { private ILazyLoader _lazyLoader; public Order(ILazyLoader lazyLoader) { this._lazyLoader = lazyLoader; } public int OrderID { get; set; } public string CustomerID { get; set; } public DateTime? OrderDate { get; set; } private ICollection<OrderDetail> _orderDetails; public ICollection<OrderDetail> OrderDetails { get => this._lazyLoader.Load(this, ref _orderDetails); set => _orderDetails = value; } } 通过代理类实现懒加载这种方式,需要单独安装 Microsoft.EntityFrameworkCore.Proxies Nuget 包,它通过 Castle.Core 框架来生成代理类来实现对导航属性的延迟加载。
启用懒加载需要注意以下两点:
在配置中启用懒加载;
实体类不能是封闭(sealed)类,导航属性必须是虚(virtual)属性。
这种方式,在以前的博客我已经分享过,只不过当时还没有发布,原文地址:Entity Framework Core 懒加载。
值转换EF Core 2.1 允许您将插入数据库的值自定义转换逻辑。例如:将属性的值进行加密与解密。
示例,将插入的值进行Base64编码,在查询的时候进行Base64解码。