我有以下内容(为了清楚起见,缩写) - 枚举,具有该枚举的基类,以及两个将枚举设置为特定值的派生类。
public enum MyEnum
{
Value1, Value2
}
public class MyBaseClass
{
public MyEnum { get; protected set; }
}
public class DerivedOne: MyBaseClass
{
public DerivedOne { MyEnum = MyEnum.Value1; }
}
public class DerivedTwo: MyBaseClass
{
public DerivedTwo { MyEnum = MyEnum.Value2; }
}
我想要做的是让Entity Framework 5自动区分DerivedOne和DerivedTwo,使用基于MyEnum值的鉴别器。我应该能够做到这一点,按照惯例,每个MyEnum == MyEnum.Value1代表DerivedOne,而MyEnum == MyEnum.Value2代表DerivedTwo。
我在DbContext中试过这个:
public class MyDbContext : DbContext
{
DbSet<MyBaseClass> MyBaseClass { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyBaseClass>()
.Map<DerivedOne>(m => m.Requires(x => x.MyEnum == MyEnum.Value1));
base.OnModelCreating(modelBuilder);
}
}
但是,这将抛出以下InvalidOperationException:
表达式'x =&gt; (Convert(x.MyEnum)== 0)'不是有效的属性表达式。表达式应表示属性(...)
编辑:我相信我使用它更进一步:
modelBuilder.Entity<MyBaseClass>().Map<DerivedOne>(m => m.Requires("MyEnum")
.HasValue((Int32)MyEnum.Value1));
现在我得到这个EntityCommandCompilationException:
从行开始映射片段的问题(...)映射条件成员'MyBaseClass.MyEnum',其条件不是'IsNull = False'。删除MyBaseClass.MyEnum上的条件或从映射中删除它。
有关如何解决此问题的任何提示?谢谢!
答案 0 :(得分:7)
据我所知你不能这样做。使用显式Requires
来指定说明者只是为了给它一个name
- 不要将它连接到你的财产。
据我所知,这总是导致你所描述的错误(后来)。如果你想指定鉴别器,它必须是'自动'的(至少我从未设法定义它)
但你真的不需要。 'enum'和鉴别符是built into
你得到的类型 - 根据鉴别符值,EF / CF构建'Base`或'DerivedOne'或DerivedTwo。
因此,要实现您想要的功能,您可以执行以下操作...
public class MyBaseClass
{
[NotMapped()]
public virtual MyEnum MyEnum { get { return MyEnum.Base; } }
}
public class DerivedOne: MyBaseClass
{
public string OneProp { get; set; }
public override MyEnum MyEnum { get { return MyEnum.One; } }
}
public class DerivedTwo: MyBaseClass
{
public string TwoProp { get; set; }
public override MyEnum MyEnum { get { return MyEnum.Two; } }
}
或者只使用is
代替(如果它适合你)......
if (entity is MyBaseClass) // instead of enum
或查询...
.OfType<MyBaseClass>();
答案 1 :(得分:4)
从EF 6.1开始,我实际上能够使用枚举作为鉴别器列,尽管有这样的错误:
附加信息:“MyEnum”类型的值不能用作类型鉴别器值。支持的类型包括byte,signed byte,bool,int16,int32,int64和string。
我所要做的就是这样:
public enum MyEnum
{
Value1, Value2
}
public class MyBaseClass
{
public MyEnum { get; protected set; }
}
public class DerivedOne: MyBaseClass
{
public DerivedOne()
{
MyEnum = MyEnum.Value1;
}
}
public class DerivedTwo: MyBaseClass
{
public DerivedTwo()
{
MyEnum = MyEnum.Value2;
}
}
public class MyDbContext : DbContext
{
DbSet<MyBaseClass> MyBaseClass { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations
.Add(new DerivedOneConfiguration())
.Add(new DerivedTwoConfiguration());
}
}
public class DerivedOneConfiguration : EntityTypeConfiguration<DerivedOne>
{
public DerivedOneConfiguration()
{
Map<DerivedOne>(_ => _.Requires("MyEnum").HasValue((int)MyEnum.Value1).IsRequired());
}
}
public class DerivedTwoConfiguration : EntityTypeConfiguration<DerivedTwo>
{
public DerivedTwoConfiguration()
{
Map<DerivedTwo>(_ => _.Requires("MyEnum").HasValue((int)MyEnum.Value2).IsRequired());
}
}
所以秘密是使用(int)MyEnum.Value*
代替MyEnum.Value*
...
答案 2 :(得分:2)
基于@rsenna的答案,但更新了基于Microsofts Fluent Api原始文档的映射。
https://msdn.microsoft.com/en-us/library/jj591617%28v=vs.113%29.aspx?f=255&MSPPError=-2147217396
public enum MyEnum
{
Value1, Value2
}
public class MyBaseClass
{
[NotMapped]
public MyEnum MyEnum { get; protected set; }
}
public class DerivedOne: MyBaseClass
{
public DerivedOne()
{
MyEnum = MyEnum.Value1;
}
}
public class DerivedTwo: MyBaseClass
{
public DerivedTwo()
{
MyEnum = MyEnum.Value2;
}
}
public class MyDbContext : DbContext
{
DbSet<MyBaseClass> MyBaseClass { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<MyBaseClass>()
.Map<DerivedOne>(x => x.Requires("MyEnum").HasValue((int)MyEnum.Value1))
.Map<DerivedTwo>(x => x.Requires("MyEnum").HasValue((int)MyEnum.Value2));
}
}
答案 3 :(得分:0)
我想知道向MyEnum
添加第三个值来表示基类是否会有所帮助。
然后在构造函数中将MyBaseClass.MyEnum
设置为该特定的“默认” enum
值。
我认为每个继承人表结构需要每个类型都必须具有有效的区分符。因此,您有3种类型:
MyBaseClass
DerivedOne
DerivedTwo
即使您的应用程序永远不会使用其基本形式的MyBaseClass,EF仍然需要有效的鉴别符映射。
答案 4 :(得分:0)
从EF Core开始,您可以直接在Fluent API上使用枚举。如果未映射MyBaseClass,则可以删除描述基本标识符的第一行 HasValue 行。
use Doctrine\Common\Inflector\Inflector;
public class Server {
public function setParameters($params) {
foreach ($params as $k => $p) {
if (!is_null($p)) { // here is the if statement
$key = Inflector::camelize($k);
if (property_exists($this, $key)) {
$this->{'set' . ucfirst($key)}($p);
}
}
}
return $this;
}
}