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