EF Core 2.1變化

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

相關文章
相關標籤/搜索