Regarding Discriminator in EF Core, is there a way to set the base class with all values?
Asked Answered
M

3

7

I want that when retrieving the base class I should get all rows in the table disregarding the discriminator. I only want to use the discriminator when retrieving one of the derived classes. How can I accomplish that?

The first thing that I tried was to only set HasValue for the derived classes but not the base class like this...

modelBuilder.Entity<BaseClass>(entity =>
{
   entity.HasDiscriminator(e => e.DiscriminatorProperty)
     // .HasValue<BaseClass>()
     .HasValue<DerivedClass1>(1)
     .HasValue<DerivedClass2>(2);
});

...but that gives me the following error:

An exception of type 'System.InvalidOperationException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'The entity type 'BaseClass' is part of a hierarchy, but does not have a discriminator value configured.'

Another thing that I tried was to configure the BaseClass for each possible discriminator value like this...

modelBuilder.Entity<BaseClass>(entity =>
{
   entity.HasDiscriminator(e => e.DiscriminatorProperty)
     .HasValue<BaseClass>(1)
     .HasValue<BaseClass>(2)
     .HasValue<DerivedClass1>(1)
     .HasValue<DerivedClass2>(2);
});

...but when actually trying to retrieve the base class, I only got records with discriminator value of 1. EF Core seemed to only recognize the first configuration and ignore the next.

So my question is how can I configure the discriminator specifically for the derived classes but not for the base class? In other words when retrieving the base class I should get all of the records in the table.

Martelle answered 29/1, 2020 at 22:56 Comment(1)
I'm facing the same issue. I want to get all rows by base class but I don't want to inherit all 500+ derived types. My app just needs 2 of all possible derived types. Also, the DB model is kind of dynamic, so new types might come in on the fly... Would be great to have something like .HasAnyValue<BaseClass>()Canvas
C
3

EF Core documentation says

When querying for derived entities, which use the TPH pattern, EF Core adds a predicate over discriminator column in the query. This filter makes sure that we don't get any additional rows for base types or sibling types not in the result. This filter predicate is skipped for the base entity type since querying for the base entity will get results for all the entities in the hierarchy.

This suggests to me that your code should be:

modelBuilder.Entity<BaseClass>(entity =>
{
   entity.HasDiscriminator(e => e.DiscriminatorProperty)
     .HasValue<BaseClass>(0)
     .HasValue<DerivedClass1>(1)
     .HasValue<DerivedClass2>(2);
});

Then, even if your db only has discriminator values of 1 or 2, a query for BaseClass will get all rows.

Cookery answered 21/2, 2022 at 15:22 Comment(1)
Just to note that my answer almost two years ago was entirely theoretical, but experience since has confirmed it.Cookery
M
1

When you save a derived class to the database, then select it back, Entity Framework will construct the derived class and return it. This is by design.

If you don't need to save instances of the base class, it should be abstract.

Of course you can always .Select() only the fields of the base class that you need for any particular query.

Mcadoo answered 19/10, 2020 at 3:50 Comment(0)
C
0

To avoid the hierarchy issue, you need to mark your base class as abstract. (your modelBuilder only needs the derived classes, not the base class)

Cuticle answered 19/10, 2020 at 2:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.