簡體   English   中英

Entity Framework Core 約定在哪里?

[英]Where are Entity Framework Core conventions?

使用 EF 6.1+ 有時我們需要添加或刪除現有的內容。 代碼看起來或多或少像:

public class MyContext : DbContext
    {
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.AddFromAssembly(Assembly.GetExecutingAssembly());
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
                modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
                modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

                base.OnModelCreating(modelBuilder);
            }
}

如何在 EF 核心中做同樣的事情? 模型構建器沒有約定屬性:(

我正在將一些代碼從 EF 移植到 EF Core 2.1+ 並且迫不及待地等待 EF Core 3.0 所以寫了一些擴展方法,它們有點幫助..

public static IEnumerable<IMutableEntityType> EntityTypes(this ModelBuilder builder)
{
    return builder.Model.GetEntityTypes();
}

public static IEnumerable<IMutableProperty> Properties(this ModelBuilder builder)
{
    return builder.EntityTypes().SelectMany(entityType => entityType.GetProperties());
}

public static IEnumerable<IMutableProperty> Properties<T>(this ModelBuilder builder)
{
    return builder.EntityTypes().SelectMany(entityType => entityType.GetProperties().Where(x => x.ClrType == typeof(T)));
}

public static void Configure(this IEnumerable<IMutableEntityType> entityTypes, Action<IMutableEntityType> convention)
{
    foreach (var entityType in entityTypes)
    {
        convention(entityType);
    }
}

public static void Configure(this IEnumerable<IMutableProperty> propertyTypes, Action<IMutableProperty> convention)
{
    foreach (var propertyType in propertyTypes)
    {
        convention(propertyType);
    }
}

例如,通過這些,您可以編寫類似於 EF 6.1.x 中的約定。

// equivalent of modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.EntityTypes()
            .Configure(et => et.Relational().TableName = et.DisplayName());

// Put the table name on the primary key
modelBuilder.Properties()
            .Where(x => x.Name == "Id")
            .Configure(p => p.Relational().ColumnName = p.DeclaringEntityType.Name + "Id");

// Mark timestamp columns as concurrency tokens
modelBuilder.Properties()
            .Where(x => x.Name == "Timestamp")
            .Configure(p => p.IsConcurrencyToken = true);

對於 EF Core 3.0,元模型方法略有變化,因此您需要

modelBuilder.EntityTypes()
            .Configure(et => et.SetTableName(et.DisplayName()));

modelBuilder.Properties()
            .Where(x => x.Name == "Id")
            .Configure(p => p.SetColumnName(BaseName(p.DeclaringEntityType.Name) + "Id"));

還沒有檢查過這個效率,但除非你的模型很大,否則應該不會造成問題

這可以使用外鍵、索引等的其他助手進行擴展

看起來它仍然不在 EF Core 2.0 中。 所以這是實現它的一種方法。 我這樣做是為了將一致的行為應用於某些屬性,但要解決您問題中的示例,您可以嘗試以下操作:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // equivalent of modelBuilder.Conventions.AddFromAssembly(Assembly.GetExecutingAssembly());
    // look at this answer: https://stackoverflow.com/a/43075152/3419825

    // for the other conventions, we do a metadata model loop
    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        // equivalent of modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        entityType.Relational().TableName = entityType.DisplayName();

        // equivalent of modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        // and modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
        entityType.GetForeignKeys()
            .Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade)
            .ToList()
            .ForEach(fk => fk.DeleteBehavior = DeleteBehavior.Restrict);
    }

    base.OnModelCreating(modelBuilder);
}

你應該可以用entityType做很多事情

為了在 EF Core 5 中設置單數表名,您可以執行以下操作

modelBuilder.Model.GetEntityTypes()            
    .Configure(et => et.SetTableName(et.DisplayName()));

但是如果你的域中有值對象,它們都將被視為實體類型並在數據庫中創建為表。 如果您的值對象都繼承自ValueObject類的基本類型,您可以使用以下內容:

modelBuilder.Model.GetEntityTypes()            
    .Where(x => !x.ClrType.IsSubclassOf(typeof(ValueObject)))
    .Configure(et => et.SetTableName(et.DisplayName()));

EF Core 5 的另一個缺點是,當您在實體模型中使用繼承時,設置表名稱會從Table-per-Hierarchy (TPH) 更改為Table-per-Type (TPT)

您可以使用以下替代方法(假設您的實體來自BaseEntity

modelBuilder.Model.GetEntityTypes()
    .Where(x => x.ClrType.BaseType == typeof(BaseEntity))
    .Configure(et => et.SetTableName(et.DisplayName()));

其中 Configure 定義為擴展方法:

public static class ModelBuilderExtensions
{
    public static IEnumerable<IMutableEntityType> EntityTypes(this ModelBuilder builder)
    {
        return builder.Model.GetEntityTypes();
    }
    public static IEnumerable<IMutableProperty> Properties(this ModelBuilder builder)
    {
        return builder.EntityTypes().SelectMany(entityType => entityType.GetProperties());
    }

    public static IEnumerable<IMutableProperty> Properties<T>(this ModelBuilder builder)
    {
        return builder.EntityTypes().SelectMany(entityType => entityType.GetProperties().Where(x => x.ClrType == typeof(T)));
    }

    public static void Configure(this IEnumerable<IMutableEntityType> entityTypes, Action<IMutableEntityType> convention)
    {
        foreach (var entityType in entityTypes)
        {
            convention(entityType);
        }
    }

    public static void Configure(this IEnumerable<IMutableProperty> propertyTypes, Action<IMutableProperty> convention)
    {
        foreach (var propertyType in propertyTypes)
        {
            convention(propertyType);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM