C# 实体框架4通过反射的代码优先继承解决方案
我已经找到了一些解决这个问题的方法,有些不起作用,有些违反了干燥原则 我想让我的所有实体继承自C# 实体框架4通过反射的代码优先继承解决方案,c#,entity-framework,reflection,inheritance,ef-code-first,C#,Entity Framework,Reflection,Inheritance,Ef Code First,我已经找到了一些解决这个问题的方法,有些不起作用,有些违反了干燥原则 我想让我的所有实体继承自Audit(它提供属性/列IsActive,CreateDate,UpdateDate,CreateUser,&UpdateUser)。我可以让它正常工作,但这会导致使用关系生成的列名出现问题(CreateUser\u UserId&UpdateUser\u UserId)。我更喜欢CreateUserId和UpdateUserId。不幸的是,ColumnAttribute似乎不像文章那样工作,所以答案
Audit
(它提供属性/列IsActive
,CreateDate
,UpdateDate
,CreateUser
,&UpdateUser
)。我可以让它正常工作,但这会导致使用关系生成的列名出现问题(CreateUser\u UserId
&UpdateUser\u UserId
)。我更喜欢CreateUserId
和UpdateUserId
。不幸的是,ColumnAttribute
似乎不像文章那样工作,所以答案是这样的。然而,fluentapi确实可以工作。它只是因为我创建的每一个实体,我最终都必须这样做:
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
// have to write these two lines for each new entity I create
modelBuilder.Entity<User>().HasOptional(u => u.CreateUser).WithMany().HasForeignKey(u => u.CreateUserId).WillCascadeOnDelete(false);
modelBuilder.Entity<User>().HasOptional(u => u.UpdateUser).WithMany().HasForeignKey(u => u.UpdateUserId).WillCascadeOnDelete(false);
}
这基本上是我在C#/.Net中做的第一件真实的事情,我觉得它非常复杂。如果我完全错了,请给我一个不适合我的选择。我真的不喜欢T4模板或接口的想法-这是我不想维护的重复代码。是审计实体本身吗?如果是,您可以直接在审计中应用这些规则 我还认为使用继承是不好的。我将使用复杂类型属性。见:
为什么要更改DB模式的生成方式。特别是首先使用代码,这应该是隐藏的。我看到改变这个的唯一原因是当您已经有了DB模式并且想要为它创建映射时。是审计实体本身吗?如果是,您可以直接在审计中应用这些规则 我还认为使用继承是不好的。我将使用复杂类型属性。见: 为什么要更改DB模式的生成方式。特别是首先使用代码,这应该是隐藏的。我看到更改此方法的唯一原因是当您已经有了DB schema并希望为其创建映射时。创建帮助器方法:
private void MapUserRelations<TEntity>(DbModelBuilder modelBuilder)
where TEntity : Audit
{
modelBuilder.Entity<TEntity>().HasOptional(u => u.CreateUser).WithMany().HasForeignKey(u => u.CreateUserId).WillCascadeOnDelete(false);
modelBuilder.Entity<TEntity>().HasOptional(u => u.UpdateUser).WithMany().HasForeignKey(u => u.UpdateUserId).WillCascadeOnDelete(false);
}
创建辅助对象方法:
private void MapUserRelations<TEntity>(DbModelBuilder modelBuilder)
where TEntity : Audit
{
modelBuilder.Entity<TEntity>().HasOptional(u => u.CreateUser).WithMany().HasForeignKey(u => u.CreateUserId).WillCascadeOnDelete(false);
modelBuilder.Entity<TEntity>().HasOptional(u => u.UpdateUser).WithMany().HasForeignKey(u => u.UpdateUserId).WillCascadeOnDelete(false);
}
这很有魅力!我创建了
MapUserRelations
static
,相应地更改了BindingFlags
,并将OnModelCreating
的主体重构为另一个静态方法(如我所想,我将向OnModelCreating
的主体添加更多内容)。我不知道这是否应该是一个单独的问题-我如何才能使“MapUserRelations”
编译安全?@Olson:糟糕。反射不是编译安全的。什么是“糟糕的”。关于它?我说的编译安全,是指。。是否有任何语法可以有效地生成字符串“MapUserRelations”
?类似(伪语法)MyClass.MapUserRelations.ToString()
…?这就像一个符咒!我创建了MapUserRelations
static
,相应地更改了BindingFlags
,并将OnModelCreating
的主体重构为另一个静态方法(如我所想,我将向OnModelCreating
的主体添加更多内容)。我不知道这是否应该是一个单独的问题-我如何才能使“MapUserRelations”
编译安全?@Olson:糟糕。反射不是编译安全的。什么是“糟糕的”。关于它?我说的编译安全,是指。。是否有任何语法可以有效地生成字符串“MapUserRelations”
?类似于(伪语法)MyClass.MapUserRelations.ToString()
…?+1的建议。不,审核
本身不是一个实体。我浏览了你链接到的那篇文章——虽然复杂类型很好(我可能会改变我的模型使用复杂类型),但我最终还是得到了不太理想的列名。我想改变模式生成的方式,因为无论我喜欢与否,人们(包括我自己)都必须手动触摸这些列(有些事情在数据库层上更容易)。另外,覆盖它们在UI中的显示方式将更容易/更一致。建议+1。不,审核
本身不是一个实体。我浏览了你链接到的那篇文章——虽然复杂类型很好(我可能会改变我的模型使用复杂类型),但我最终还是得到了不太理想的列名。我想改变模式生成的方式,因为无论我喜欢与否,人们(包括我自己)都必须手动触摸这些列(有些事情在数据库层上更容易)。另外,覆盖它们在UI中的显示方式将更容易/更一致。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
var types = GetTypesInheritingFrom(typeof (Audit));
foreach (var t in types)
{
var method = this.GetType().GetMethod("MapUserRelations");
var generic = method.MakeGenericMethod(t, BindingFlags.NonPublic | BindingFlags.Instance);
generic.Invoke(this, new Object[] { modelBuilder });
}
}