[英]Entity Framework 5 - Enum based Discriminator for derived classes
我有以下内容(为清楚起见而缩写) - 一个枚举,一个带有该枚举的基类,以及两个将枚举设置为特定值的派生类。
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; }
}
我想要做的是让实体框架 5 自动区分 DerivedOne 和 DerivedTwo,并使用基于 MyEnum 值的 discriminator 。 我应该能够这样做,因为按照惯例,每个 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 => (Convert(x.MyEnum) == 0)' 不是有效的属性表达式。 表达式应该代表一个属性 (...)
编辑:我相信我使用这个可以走得更远:
modelBuilder.Entity<MyBaseClass>().Map<DerivedOne>(m => m.Requires("MyEnum")
.HasValue((Int32)MyEnum.Value1));
现在我得到这个 EntityCommandCompilationException:
映射从第 (...) 行开始的片段问题 映射条件成员 'MyBaseClass.MyEnum' 的条件不是 'IsNull=False'。 删除 MyBaseClass.MyEnum 上的条件或将其从映射中删除。
关于我如何解决这个问题的任何提示? 谢谢!
据我所知,你不能那样做。 做显式Requires
指定鉴别器只是给它一个name
- 而不是将它连接到您的财产。
据我所知,这总是会导致您所描述的错误(稍后)。 如果你想指定鉴别器,它必须是“自动”的(至少我从来没有设法这样定义它)
但你真的不需要那个。 “枚举”和鉴别器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>();
从 EF 6.1 开始,我实际上能够使用枚举作为鉴别器列,尽管有这个错误:
附加信息:“MyEnum”类型的值不能用作类型鉴别器值。 支持的类型包括字节、有符号字节、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*
...
从 EF Core 开始,您可以直接在 Fluent API 上使用枚举。 如果您的 MyBaseClass 未映射,您可以删除描述基本鉴别器的第一行HasValue 。
modelBuilder.Entity<MyBaseClass>()
.HasDiscriminator<MyEnum>("MyEnum")
.HasValue<MyBaseClass>(MyEnum.Value0)
.HasValue<DerivedOne>(MyEnum.Value1)
.HasValue<DerivedTwo>(MyEnum.Value2);
基于@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));
}
}
我想知道向MyEnum
添加第三个值来表示基类是否会有所帮助。 然后在构造函数中将MyBaseClass.MyEnum
设置MyBaseClass.MyEnum
特定的“默认” enum
值。
我认为 Table-per-heirarchy 结构需要每个类型都必须有一个有效的鉴别器。 因此,您有 3 种类型:
MyBaseClass
DerivedOne
DerivedTwo
即使您的应用程序永远不会以其基本形式使用 MyBaseClass,EF 仍然需要一个有效的鉴别器映射。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.