dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.75k stars 3.18k forks source link

Query :: Tracking doesn't work with coalesce and conditional #5008

Closed maumar closed 5 years ago

maumar commented 8 years ago

repro:

var query = from eVersion in ctx.Entities
                            join eRoot in ctx.Entities
                            on eVersion.RootEntityId equals (int?)eRoot.Id
                            into RootEntities
                            from eRootJoined in RootEntities.DefaultIfEmpty()
                            select eRootJoined ?? eVersion;

                var result = query.ToList();

                // returns 0 elements
                var trackedCount = ctx.ChangeTracker.Entries().ToList();
maumar commented 8 years ago

Currently we have a TrackEntities method around the query, that keeps track of which entities from the result object should be tracked - storing the list of accessors from the resulting object to the entity that is supposed to be tracked.

We compute those accessors using re-linq's AccessorFindingExpressionVisitor which currently doesn't handle Coalesce or Conditional expressions.

@MichaelKetting would you consider adding logic for those operators or perhaps some extensibility points so that we could handle additional nodes?

MichaelKetting commented 8 years ago

@maumar Ah, yes. Will need to look into this. When the AcessorFindingExpressionVisitor is used inside the transformation, support for Coalesce and Conditional isn't needed since those can be evaluated inside the SQL query and only the resulting value needs to be handled in memory.

Extension point's a bit tricky due to the way the callgraph is composed but I'll have a look at the implications of Coalesce and Conditional.

I haven't checkout out TrackEntities, am I correct in understanding that you're just tracking the objects returned by the outermost select projection?

maumar commented 8 years ago

@MichaelKetting yes, we only track entities that are part of the final result. TrackEntities method is wrapped around our last Select method. However we compute accessors earlier, because we strip QuerySourceReferenceExpressions at one point in our pipeline.

I guess we could refactor that part in EF code to compute accessors based on entity types rather than query sources themselves. This would probably mean that all entities of a particular type would be tracked/included regardless of their DbSet of origin, but that might be ok. I will look into this from my side also. Thank you for your input!