Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework 5 - Enum based Discriminator for derived classes

I have the following (abbreviated for clarity) - an enum, a base class with that enum, and two derived classes that set the enum to a specific value.

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

What I want to do, is have Entity Framework 5 automatically distinguish between DerivedOne and DerivedTwo, with a MyEnum value based discriminator. I should be able to do this as, by convention, every MyEnum == MyEnum.Value1 represents DerivedOne, and MyEnum == MyEnum.Value2 represents DerivedTwo.

I tried this in my 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);
    }
}

However, this throws the following InvalidOperationException:

The expression 'x => (Convert(x.MyEnum) == 0)' is not a valid property expression. The expression should represent a property (...)

Edit: I believe I got a little farther using this:

modelBuilder.Entity<MyBaseClass>().Map<DerivedOne>(m => m.Requires("MyEnum")
                                  .HasValue((Int32)MyEnum.Value1));

Now I get this EntityCommandCompilationException:

Problem in mapping fragments starting at line (...) Condition member 'MyBaseClass.MyEnum' with a condition other than 'IsNull=False' is mapped. Either remove the condition on MyBaseClass.MyEnum or remove it from the mapping.

Any hints on how I can solve this? Thanks!

like image 259
Alex Avatar asked Apr 07 '13 06:04

Alex


2 Answers

As of EF Core you can use Enums directly using Fluent API. If your MyBaseClass is not mapped (is an abstract class), you can remove the first HasValue line describing the base discriminator. Try the next code in your ApplicationDbContext:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyBaseClass>()
        .HasDiscriminator<MyEnum>("MyEnum")
        .HasValue<MyBaseClass>(MyEnum.Value0)
        .HasValue<DerivedOne>(MyEnum.Value1)
        .HasValue<DerivedTwo>(MyEnum.Value2);
}
like image 124
Jonathan Ramos Avatar answered Sep 19 '22 13:09

Jonathan Ramos


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));
    }
}
like image 26
Ogglas Avatar answered Sep 19 '22 13:09

Ogglas