I have some problem with using dbContext Query method on base class which provide some inheritance to one other class (just for inherit properties, not for model / db building)
In my repo services I call something like:
IEnumerable<CoasterExtended> coasters = await _db.Query<CoasterExtended>()
.FromSql(GetCoastersProcedure, pageNumberParam, pageSizeParam, orderByParam, sortParam, breweryIdParam, searchParam, coasterTypeParam)
.ToListAsync();
GetCoastersProcedure is a sql procedure which return all properties of CoasterExtended class. This class is not used to model / db build. It is just mirror of sql procedure result.
In my OnModelCreating method i just have:
builder.Query<CoasterExtended>();
Querying the result of sql procedure worked fine until I decided to use this class for inheritance:
public class CollectionItemExtended : CoasterExtended {
// some additional properties
}
And the OnModelCreating method:
builder.Query<CollectionItemExtended>();
The query (of CoasterExtended type) now return error "The required column 'Discriminator' was not present in the results of a 'FromSql' operation". I know that discriminator is used for inherited types, but I use both classes to mirror the result of separate sql procedures (these results I simply map to desired app model classes)
So I dont want to select (and fake) discriminator ... I just want to map results of sql procedures to independent classes (which I have inherited just because I dont want to duplicate properties and mappers which are following). How can I achieve that the query result will ignore inheritance and just return the described types?
The problem is that both the base and derived classes are registered as query types, thus EF Core considers them implementing the TPH database inheritance strategy (similar to normal entity types).
If you want to just share common properties, use a base class which is not registered as entity or query type.
In your case, change the name of the CoasterExtended
class to let say CoasterExtendedBase
and let both CoasterExtended
and CollectionItemExtended
inherit from it:
public class CoasterExtended : CoasterExtendedBase { }
public class CollectionItemExtended : CoasterExtendedBase
{
// some additional properties
}
Now you can register both CoasterExtended
and CollectionItemExtended
as query types and everything will work as expected.
Query
is actually superfluous here. This boils down to the logic of FromSQL
. In other words, Query<Foo>.FromSQL
is really just FromSQL<Foo>
. In short, FromSQL
can only work with entity types, i.e. types that are actually mapped to your database. This is why it's assuming relational inheritance with a Discriminator
column. In other words, it's not meant for mapping to random C# object types.
EDIT
While the above is true, it's not comprehensive. It's better said that DbSet<T>.FromSQL
must be an entity type. EF Core 2.1 added support for "query sets", but you must define such a query set on your context in order to utilize it:
public DbQuery<CollectionItemExtended> CollectionItemExtendeds { get; set; }
Then, you can utilize FromSQL
on that:
_context.CollectionItemExtendeds.FromSQL(...);