我可以在Entity Framework Code First中禁用自动关系吗?
我注意到Entity Framework在他们的最新版本中仍然有很多“automagical”功能。一如既往,这是一把真正的双刃剑。我可以在Entity Framework Code First中禁用自动关系吗?
具体来说,我使用OnModelBuilder事件在代码中使用fluentAPI(http://msdn.microsoft.com/en-us/library/hh295844(v=vs.103)的.aspx)。我有一大批实体,他们并不都遵守微软的“标准”。例如,我的ID列被命名为Person_id而不是PersonId。因此,实体并不总是自动检测表上的主键,或者至少,似乎并不这样做。
我不介意在构建模型时明确表达,但是困扰我的是我并不总是确定实体会自动检测哪些属性和关系,以及哪些属性会错误地忽略或错误标识。因为我的大多数实体也有一个带有辅助方法和属性(处理枚举的东西等)的分类,所以我非常担心有一天实体会自动在不应该映射的东西之间创建映射(失败可能是实体或一些毫无戒心的程序员)。
有没有一种方法可以禁用实体的自动关系连接功能,以便我可以在我的OnModelBuilder方法100%显式?或者,至少我怎么知道什么时候需要添加额外的映射细节(例如需要声明一个可选字段,或者何时不会自动检测特定的导航属性)?
谢谢!
只要明确你的关系,你的实体配置中的关键和列,它确实不应该是一个问题。
我个人在编码的时候,让它假设直到断开,然后我改正配置。
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<AccountWriteContext>(null);
modelBuilder.Configurations.Add(new AccountEntityTypeConfiguration());
modelBuilder.Configurations.Add(new AccountOwnerEntityTypeConfiguration());
modelBuilder.Configurations.Add(new CreditCardEntityTypeConfiguration());
modelBuilder.Configurations.Add(new TenantEntityTypeConfiguration());
//blah blah blah
}
class AccountOwnerEntityTypeConfiguration
: EntityTypeConfiguration<AccountOwner>
{
public AccountOwnerEntityTypeConfiguration()
{
this.HasKey(p => p.ID);
this.Property(p => p.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity).IsRequired();
this.HasRequired(o => o.CreditCard).WithMany().HasForeignKey(c => c.CreditCardID).WillCascadeOnDelete(true);
this.ToTable("AccountOwner", "AccountWrite");
}
}
我会推荐使用数据注释属性来做到这一点。例如,[key]
属性可用于定义您的主键,并且[table]
属性可用于提供您的表的名称。 [required]
属性可用于告知EF需要一个字段。
在我看来,使用属性语法要比使用流畅语法更新模型容易得多,而且它也是自我记录,因为属性直接放置在对象代码中。
欲了解更多信息,请参阅本博客文章,列出了所有可用的属性:
问题是“如何禁用”。我假设没有明确告诉哪些列禁用。不管你喜欢注释还是流利的语法,这都是无关紧要的。目标是有一个稳定的映射,而不需要明确告诉忽略新的属性... – baHI
其实这个代码删除所有公约,甚至清除初始设置...
...但还是不EntityTypeConfiguration映射列映射...
private void RemoveAllConventions(DbModelBuilder modelBuilder)
{
new List<string>()
{
"_configurationConventions",
"_conceptualModelConventions",
"_conceptualToStoreMappingConventions",
"_storeModelConventions"
}
.ForEach(field =>
{
var values =
(IEnumerable<IConvention>)typeof(ConventionsConfiguration)
.GetField(field, BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic)
.GetValue(modelBuilder.Conventions);
modelBuilder.Conventions.Remove(values.ToArray());
});
var initialCS = typeof(ConventionsConfiguration)
.GetField("_initialConventionSet", BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic)
.GetValue(modelBuilder.Conventions);
new List<string>()
{
"ConfigurationConventions",
"ConceptualModelConventions",
"ConceptualToStoreMappingConventions",
"StoreModelConventions"
}
.ForEach(field =>
{
var values =
(IEnumerable<IConvention>) initialCS
.GetType()
.GetProperty(field, BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public)
.GetValue(initialCS);
modelBuilder.Conventions.Remove(values.ToArray());
});
}
发布的代码是否回答了问题并不十分清楚。这是你目前的状况,但它仍然不起作用?或者这是否解决了这个问题,但会导致其他问题? – Tunaki
好,因为去除的惯例不起作用,有一种简单的方法可以不映射EF6中的所有非配置属性。x
基本的是使用单独的映射类,并且在类内部执行手动映射之后,只需调用一个方法,即使用反射将强制忽略所有未配置的属性。
下面是我的要点链接,其中的实施。还添加了一个样本作为评论:https://gist.github.com/hidegh/36d92380c720804dee043fde8a863ecb
这应该适用于所有属性,因此也适用于集合(1:n)或其他引用(n:1) – baHI
如果这东西让你担心,你可能应该使用EF的“设计优先”方面而不是更新的“代码优先”东西 –
我顺便开始使用EDMX。我试图'升级'为代码优先,认为它可能更容易管理,因为它都在代码中,但它可能不值得花费精力和时间进行调试。 – Brett