【问题标题】:Where are Entity Framework Core conventions?Entity Framework Core 约定在哪里?
【发布时间】:2018-03-31 22:44:15
【问题描述】:

在使用 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 核心中做同样的事情? Modelbuilder 没有 Conventions 属性:(

【问题讨论】:

标签: c# entity-framework-core


【解决方案1】:

看起来它仍然不在 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做很多事情

【讨论】:

  • entityType.Relational().TableName = entityType.DisplayName();如果 entityType 是“拥有”类型,则可能很危险。如果 entityType 是“拥有”类型,则 DisplayName() 返回所有者表名称。这会搞乱数据库设计。迁移脚本。
  • @thomasgalliker 有解决方案吗?
  • 同时,我只是过滤了 IsOwned() == true 的类型。看看这行代码:github.com/thomasgalliker/EntityFramework.Toolkit.EFCore/blob/…
【解决方案2】:

我正在将一些代码从 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"));

尚未检查效率,但除非您的模型很大,否则不会造成问题

这可以通过其他外键、索引等助手进行扩展

【讨论】:

  • .net core 3.1 中有吗??
【解决方案3】:

为了在 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);
        }
    }
}

【讨论】:

  • 当我尝试这样做时得到'IEnumerable&lt;IMutableEntityType&gt;' does not contain a definition for 'Configure'
  • @JonathanLandrum 对不起,我错过了。答案已更新。为模型构建器添加了扩展方法
猜你喜欢
  • 2019-04-19
  • 2018-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-17
相关资源
最近更新 更多