Can I access the discriminator value in TPH mappin

2019-02-08 13:51发布

Using Entity Framework 4 CTP5 Code First and this example

Is it possible to access the discriminator value?

I would like to use it in a projection like

context.BillingDetails.Select(x => new { Number = x.Number, DiscrimitatorValue = /* how do I get the discriminator value? */ });

From this post I understand the discriminator cannot be mapped to a property but is there any other way of accessing it?

6条回答
兄弟一词,经得起流年.
2楼-- · 2019-02-08 13:56

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.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-02-08 13:56

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.

查看更多
唯我独甜
4楼-- · 2019-02-08 14:01

Why don't you use the following query instead?

 var q = con.BillingDetails.OfType<BankAccount>().ToList();
查看更多
Animai°情兽
5楼-- · 2019-02-08 14:04

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.

查看更多
叼着烟拽天下
6楼-- · 2019-02-08 14:14

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";
    }
}
查看更多
The star\"
7楼-- · 2019-02-08 14:20

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.

查看更多
登录 后发表回答