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,不知道楊老師啥時候更新下。