1

我有一个基类重用与实体框架6.0,流利的API必需的属性一栏,并DataAnnotations

public class BaseClass 
{ 
    public int Id {get; set;} 
} 

和两个派生类

public class Foobar: BaseClass 
{ 
    [Required] 
    public int Whatever {get; set;} 
} 

public class Snafu: BaseClass 
{ 
    [Required] 
    public int Whatever {get; set;} 
} 

我使用表,每个层级继承并试图削减我的重复列,所以用流利的API我已经映射他们像这样:

 modelBuilder.Entity<Foobar>().Property(fb => fb.Whatever).HasColumnName("Whatever"); 
     modelBuilder.Entity<Snafu>().Property(sf => sf.Whatever).HasColumnName("Whatever"); 

然而,这导致在

(137,10):错误3023:问题在映射片段起始于线137:在表列的BaseClass BaseClass.Whatever必须映射:它没有缺省值和不可为空。

在EF6中,如果从两个子类中取掉[Required]属性,此类映射似乎工作正常。将[DefaultValue(0)]属性添加到两个派生类都不能解决问题。

任何想法如何让这些属性共享数据库中的列,同时保持其必需的属性?

+0

我不知道你为什么没有基类中的“无论”?这个属性可以在你的子类型中使用。 – PilotBob

+0

这些类仅用于演示目的。在几个派生类中的实际应用程序中,只有一对共享一个不在基类中的属性,以及这些属性由接口强制执行的派生类。 – joelmdev

+0

找到一个已验证的错误,仍然没有得到upvote:\ – joelmdev

回答

2

这实际上是在EF6的错误。在EF5中,所用的场景根本不起作用(我们会在“列名称必须是唯一的”行中引发异常)。虽然在EF6中我们做了一些工作来启用它,但显然我们错过了共享列必须在数据库中可以为空的事实,即使属性在派生类型中是必需的。后者是因为除非基类是抽象的,你需要能够存储基类型的实例,并且对于任何基类型的实例,列应该为空。

我已经提交的问题,在我们的bug数据库:

https://entityframework.codeplex.com/workitem/1924

随意选它。

至于解决方法,如果有一个中间类型不是一个选项,您可以将该列标记为可为空,并在实体配置上明确附加一个对.IsOptional()的调用。这不会给你到底想要什么,因为为了EF数据验证的目的,对流利API的IsOptional()的调用将覆盖[Required]数据注释。但是,其他类型的数据验证(例如MVC验证)仍将遵循该属性。

还有其他可能的解决方法,我还没有尝试过,也许如果它是可以接受的使用TPT和两种派生类型都无论生活在不同的表中,这将工作。我相信任何依赖于设置默认值的方法都无济于事,因为该错误不仅仅是表格模式无法保存基类的实例,它还与Code First生成的EF映射有关有效。

更新:这将在当前可用的实体框架版本6.1.0中修复。

0

介绍另一种类型,其中包含由其他两个共享的必需属性完成您正在寻找的内容。实体再看看这个:

public class BaseClass 
{ 
    public int Id { get; set; } 
} 
public abstract class BaseIntermediaryClass : BaseClass 
{ 
    [Required] 
    public int Whatever { get; set; } 

} 
public class Foobar : BaseIntermediaryClass 
{ 
} 

public class Snafu : BaseIntermediaryClass 
{ 
} 

而且这样的映射:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<BaseIntermediaryClass>().Property(fb => fb.Whatever).HasColumnName("Whatever"); 
     base.OnModelCreating(modelBuilder); 
    } 

工作示例的完整代码可以在这里找到:https://gist.github.com/trayburn/7923392

+0

这是我曾考虑过的解决方案,但我真的不想在一个属性上继承一个子类,我宁愿只使用一个接口(也许这是不好的做法?)。在这一点上,我只是想了解为什么我能够做我想要做的事情,为非必需的属性,甚至是基元,而不是所需的属性。如果我把它标记为一个班级的要求,而不是另一个班级,它甚至可以工作。 – joelmdev

相关问题