实体框架核心约定在哪里?

时间:2017-10-19 19:37:03

标签: c# entity-framework-core

使用EF 6.1+时,我们需要添加或删除现有的conentions。代码看起来或多或少像:

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核心如何做同样的事情?模型构建器没有约定属性:(

3 个答案:

答案 0 :(得分:12)

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

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

这可以与其他帮助程序一起扩展,以用于外键,索引等

答案 1 :(得分:9)

看起来它仍然不在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

做很多事情

答案 2 :(得分:1)

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