EF Core 2.1随.NET Core 2.1一块儿发布,本篇文章总结一下EF Core的新增功能,先从简单的开始说。数据库
1、延迟加载数组
延迟加载不用介绍了吧,直接看一下怎样配置吧。EF Core 2.1默认是不容许延迟加载的,想要使用这个特性必须调用UseLazyLoadingProxies方法,这个扩展方法在 Microsoft.EntityFrameworkCore.Proxies 包中。ide
在Startup中配置:ui
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<TestContext>(options => { options.UseLazyLoadingProxies().UseSqlServer("yourConnectionString"); }); }
也可在DbContext中重写OnConfiguring方法中配置:this
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseLazyLoadingProxies().UseSqlServer("yourConnectionString"); }
配置好后在实体类中对应的属性上加上 virtual 关键字就OK,用法和EF6没区别。除了加 virtual 标记外,EF Core 2.1还能够经过 ILazyLoader 类型的对象来实现延迟加载,实现以下:编码
public class Person { public Person() { } public Person(ILazyLoader lazyLoader) { LazyLoader = lazyLoader; } public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } private ILazyLoader LazyLoader { get; set; } private ICollection<Child> _children; public virtual ICollection<Child> Children { get => LazyLoader?.Load(this, ref _children); set => _children = value; } }
ILazyLoader在 Microsoft.EntityFrameworkCore.Abstractions 程序集中。按照官方文档所述,除了注入 ILazyLoader 类型使用LazyLoader外还能够注入Action<object,string>类型来实现LazyLoader,但我尝试的时候报错,若是有尝试成功的但愿能在留言区里留言,多谢。spa
2、支持GroupBy3d
这个特性就很少说了,使用方法和EF6没区别。code
3、支持TransactionScope对象
这个特性也和EF6同样,终于能够随时随地使用事务了。
4、Data Seeding
这个功能是用来初始化数据的,在进行数据库迁移时,EF会往数据库中插入一些数据,实现以下:
public class PersonConfig : IEntityTypeConfiguration<Person> { public void Configure(EntityTypeBuilder<Person> builder) { builder.HasData(new Person[] { new Person { Id = 1, Name ="张三", Age = 30 } }); } }
使用EntityTypeBuilder下的HasData就能够实现该功能。但使人感到奇怪的是,就算Id是自增加的EF也会要求Id有值!并且也不支持同时插入子表的数据。
public class PersonConfig : IEntityTypeConfiguration<Person> { public void Configure(EntityTypeBuilder<Person> builder) {
builder.HasData(new Person[] { new Person { Id = 1, Name ="张三", Age = 30, Children = new List<Child> { new Child { Id = 1, Name = "小张三", Age = 5, PersonId = 1 }, new Child { Id = 2, Name = "小小张三", Age = 1, PersonId = 1 } } } }); }
}
上面的代码,在进行数据迁移时,Children的数据不会插入到数据库中,不知道之后是否会支持关联属性的数据导入。
5、值转换
这个功能简单来讲就是将属性的类型转换成数据库中的类型(好比枚举转换成字符串),实例中能够这样写:
public class Person { public Person() { } public Person(ILazyLoader lazyLoader) { LazyLoader = lazyLoader; } public int Id { get; set; } public string Name { get; set; } public int Age { get; set; } public Gender Gender { get; set; } private ILazyLoader LazyLoader { get; set; } private ICollection<Child> _children; public virtual ICollection<Child> Children { get => LazyLoader?.Load(this, ref _children); set => _children = value; } } public enum Gender { 男, 女 }
而后再配置一下:
public class PersonConfig : IEntityTypeConfiguration<Person> { public void Configure(EntityTypeBuilder<Person> builder) { builder.Property(p => p.Gender).HasConversion(v => v.ToString(), v => (Gender)Enum.Parse(typeof(Gender), v)).IsRequired().HasMaxLength(2); } }
这里有个问题比较奇怪,我在配置类中加上这段配置并在HasData中给Gender赋值,使用Migration的时候发现若是不加 IsRequired 他竟然不给我把Gender的数据给导入到数据库里面!!!
除了基本的枚举转字符串之外,EF Core还提供以下的转换类:
BoolToZeroOneConverter | 将布尔值转换为0或1 |
BoolToStringConverter | 将布尔值转换为字符串(Y或N) |
BoolToTwoValuesConverter | 将布尔值转换为指定的两个值(没搞明白干吗用的) |
BytesToStringConverter | 将字节数组转换为Base64编码的字符串 |
CastingConverter | 从一种类型转换到另外一种类型(能够被C#互相转换的类型) |
CharToStringConverter | char转为string |
DateTimeOffsetToBinaryConverter | DateTimeOffset转为二进制的64位的值 |
DateTimeOffsetToBytesConverter | DateTimeOffset转为字节数组 |
DateTimeOffsetToStringConverter | DateTimeOffset转为字符串 |
DateTimeToBinaryConverter | DateTime转为带有DateTimeKind的64位的值 |
DateTimeToStringConverter | DateTime转为字符串 |
DateTimeToTicksConverter | DateTime转为ticks |
EnumToNumberConverter | 枚举转数字 |
EnumToStringConverter | 枚举转字符串 |
GuidToBytesConverter | Guid转字节数组 |
GuidToStringConverter | Guid转字符串 |
NumberToBytesConverter | 数字转字节数组 |
NumberToStringConverter | 数字转字符串 |
StringToBytesConverter | 字符串转字节数组 |
TimeSpanToStringConverter | TimeSpan转字符串 |
TimeSpanToTicksConverter | TimeSpan转ticks |
上面的这些对象的使用方式以下:
var converter = new EnumToStringConverter<Person>(); builder.Property(p => p.Gender).HasConversion(converter);
除了这种方式外,EF Core也支持直接指定类型,如:
builder.Property(p => p.Gender).HasConversion(string);
须要注意的是,不能将null进行转换,一个属性只能对应一个列作转换。
6、Query Types
这个功能用来查询数据库视图的。先建立个实体类:
public class Family { public int ParentId { get; set; } public string ParentName { get; set; } public int ParentAge { get; set; } public int ChildId { get; set; } public string ChildName { get; set; } public int ChildAge { get; set; } }
根据实体类在数据库中建立视图就行(貌似Migration不支持建立视图),SQL我就不写了。而后建立个继承自 IQueryTypeConfiguration<> 的配置类,代码以下:
public class FamilyConfig : IQueryTypeConfiguration<Family> { public void Configure(QueryTypeBuilder<Family> builder) { builder.ToView("Family_View"); } }
DbContext中使用 DbQuery<Family> 类型增长一个属性,运行下看看结果:
根据官方文档所述,该功能只能查询,不能增删改,不具备状态跟踪,不能包含具体查询类型的导航属性(既然不能有导航属性为啥这里有个lazyLoader...)。
本文总结的都是我认为有用的功能,EF Core 2.1新增的其余功能能够到移步至官方文档:https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.1
最后补充一个扩展方法,功能和EF6的AddFromAssembly方法相同。
private static bool IsIEntityTypeConfigurationType(Type typeIntf) { return typeIntf.IsInterface && typeIntf.IsGenericType && typeIntf.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>); } public static void ApplyConfigurationsFromAssembly(this ModelBuilder modelBuilder, Assembly assembly) { //筛选出继承自IEntityTypeConfiguration的类型 IEnumerable<Type> types = assembly.GetTypes().Where(t => !t.IsAbstract && t.GetInterfaces().Any(it => IsIEntityTypeConfigurationType(it))); Type typeModelBuilder = modelBuilder.GetType(); MethodInfo methodNonGenericApplyConfiguration = typeModelBuilder.GetMethods() .Where(m => m.IsGenericMethod && m.Name == nameof(ModelBuilder.ApplyConfiguration) && m.GetParameters().Any(s => s.ParameterType.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>))).First(); foreach (var type in types) { object entityTypeConfig = Activator.CreateInstance(type); //获取实体的类型 Type typeEntity = type.GetInterfaces().First(t => IsIEntityTypeConfigurationType(t)).GenericTypeArguments[0]; //经过MakeGenericMethod转换为泛型方法 MethodInfo methodApplyConfiguration = methodNonGenericApplyConfiguration.MakeGenericMethod(typeEntity); methodApplyConfiguration.Invoke(modelBuilder, new[] { entityTypeConfig }); } }
以上代码根据RuPeng.EFCore.Ext组件修改,该组件暂时不支持EF Core 2.1,GitHub已提交pr,不知道杨老师啥时候更新下。