Entity Framework 5 - Enum based Discriminator for derived classes

人走茶凉 提交于 2019-12-04 02:14:39

As far as I know you cannot do that. Doing the explicit Requires to specify the disciminator is only to give it a name - not to connect it to your property.

As far as I know that always results in that error (later) that you're describing. If you want to specify discriminator it has to be 'automatic'one (at least I never managed to define it that way)

But you don't need that really. The 'enum' and discriminator is built into the type you get back - based on the discriminator values, EF/CF is constructing either 'Base` or 'DerivedOne' or DerivedTwo.

So to implement what you want you can do the following...

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; } }
}

Or just use is instead (if it works for you)...

if (entity is MyBaseClass) // instead of enum  

or Query by...

.OfType<MyBaseClass>();

As of EF 6.1, I was in fact able to use an enum as a discriminator column, in spite of this error:

Additional information: Values of type 'MyEnum' cannot be used as type discriminator values. Supported types include byte, signed byte, bool, int16, int32, int64, and string.

All I have to do was something like this:

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());
    }
}

So the secret was using (int)MyEnum.Value* instead of MyEnum.Value*...

Based on the answer of @rsenna but updated with mapping based on Microsofts Fluent Api original documentation.

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));
    }
}

I wonder if adding a third value to MyEnum to represent the base class will help. And then set MyBaseClass.MyEnum to that particular 'default' enum value in the constructor.

I think the Table-per-heirarchy structure needs that EVERY type must have a valid discriminator. So, you have 3 types:

  1. MyBaseClass
  2. DerivedOne
  3. DerivedTwo

Even if your application won't use MyBaseClass in its base form ever, EF still needs a valid discriminator mapping for it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!