linq2db / linq2db.EntityFrameworkCore

Bring power of Linq To DB to Entity Framework Core projects
MIT License
449 stars 39 forks source link

Issue with Merge into TPH table and EF Entities #391

Open MatthieuDS opened 3 months ago

MatthieuDS commented 3 months ago

Hi

I have a problem/question and I'd like to know if someone knows a "good" solution.

This is a repo that minimally reproduces my problem (and an "alternative" to make it work) : https://github.com/MatthieuDS/Linq2DB_TPHProblem

So, in brief, I have a base class, BaseEntity with a Discriminator calledType. I have two entities that inherit from BaseEntity, Type1Entity and Type2Entity that are discriminated by Type (thus are saved inside one table).

My problem, I think, is that EF Core, when querying DbSet automatically adds a Where condition to the "IQueryable".

So when I do var destinationTable = linq2DB.GetTable<Type1Entity>(); For example, I see that the query adds a .Where condition (WHERE Type = ...)

When I try to do

var destinationTable = linq2DB.GetTable<Type1Entity>();

tempTable
    .Merge()
    .Using(destinationTable)
    .On((target, source) => target.Id == source.Id)
    .InsertWhenNotMatched()
    .UpdateWhenMatched()
    .DeleteWhenNotMatchedBySourceAnd(i => i.Type == EntityType.Type1)
    .Merge();

It throws the following error:

System.NotImplementedException: Currently, only Tables and CTEs are supported as the target of a merge. You can fix by calling .AsCte() before calling .Merge()
   at LinqToDB.Linq.Builder.MergeBuilder.Merge.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)

And I'm pretty sure it's because a Where condition is added to the Queryable, and the merge statement can't handle that.

The WHERE Type = ... condition on the SELECT is not really necessary in my case, as I could handle it in code, for example .DeleteWhenNotMatchedBySourceAnd(i => i.Type == EntityType.Type1) (or, in an ideal scenario, it could automatically be added to the MERGE statement).

I tried multiple solutions:

  1. linq2DB.GetTable<BaseEntity>().Cast<Type1Entity>()
  2. .AsCte()
  3. Working with BaseEntity instead of Type1Entity: This works, but then I lose the possibility to automatically update / insert properties from e.g. Type1Entity
  4. Working with a custom defined entity where I add my attributes onto it: this is currently my best solution, but ideally I'd like to be able to use my EF Core Entities and not "duplicate" my models

Thanks in advance for your help / insights.