Can I access the discriminator value in TPH mapping with Entity Framework 4 CTP5

跟風遠走 提交于 2019-11-30 11:49:30

I may be late to the game on this one, but I just added a getter property to the base class that returned the name of the current type:

public string DiscriminatorValue {
    get {
        return this.GetType().Name;
    }
}

Since by default EF is going to use this same value for the Discriminator field, they will match up.

After further information from Morteza Manavi in the comments of his post the simple answer is no

you should be aware that the discriminator column is used internally by Code First and you cannnot read/write its values from an inheritance mapping standpoint.

To access the discriminator I would have to execute a SqlQuery against the database or change my mapping strategy.

In EF Core 2.1 (I haven't checked previous versions) it's enough to add Discriminator to the base abstract class as private set property. It will be mapped with adequate value.

public abstract class Entity
{
    public int Id { get; set; }
    public string Discriminator { get; private set; }
}

EF by itself will automatically insert appropriate discriminator value to the database and will automatically set it to an object on read.

Reason aside, I recently ran into the same problem but believe this is still relevant for v4 of the EF Framework.

First, create a view which selects the discriminator value into two columns.

create view dbo.vw_BillingDetail
as
    select BillingDetailId, DiscriminatorValue, DiscriminatorValue as DiscriminatorValue2 from dbo.BillingDetail
go

Secondly, map the view to your entity during context creation:

modelBuilder
    .Entity<BillingDetail>()
    .HasKey(n => n.BillingDetailId)
    .Map(map =>
    {
        map.ToTable("vw_Person");
    })

Thirdly, define your discriminator mapping for your derived class using one of the columns in your view:

.Map<MyDerivedBillingDetail>(map =>
{
    map.Requires("DiscriminatorValue2").HasValue("YourValue");
})

Finally, define a getter and a private setter for the other discriminator column in your view with the DatabaseGenerated annotation set as Computed to prevent EF from updating/inserting for this field:

class BillingDetail
{
    public BillingDetailId { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DiscriminatorValue { get; private set; }
}

You can change the private setter to be protected and set this value explicitly during the construction of your derived entities so that the discriminator has a value prior to being persisted:

class MyDerivedBillingDetail : BillingDetail
{
    public MyDerivedBillingDetail()
    {
        this.DiscriminatorValue = "MyValue";
    }
}
Devart

Why don't you use the following query instead?

 var q = con.BillingDetails.OfType<BankAccount>().ToList();

To expand on @Michael Black's answer for Entity Framework Core 2.1 (earlier? tested in 2.1.4)

You can use any property name, database field name and data type you want.

Create a property:

[Column("foo_type_id")]
class Foo {
    public FooTypesEnum TypeId {get; set;}
}

Then in your context class with the fluent API via modelBuilder:

modelBuilder.Entity<Foo>(b => {
    b.HasDiscriminator(foo => foo.TypeId)
        .HasValue<SubFooA>(FooTypesEnum.SubFooA)
        .HasValue<SubFooB>(FooTypesEnum.SubFooB);
});

This is really useful if you need to build composable queries that e.g., group on the discriminator, etc.

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