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?
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.
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.
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.
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";
}
}
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.
Why don't you use the following query instead?
var q = con.BillingDetails.OfType<BankAccount>().ToList();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With