-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Entity not tracked by change tracker when selecting not mapped property #15989
Comments
Note for triage: this is a very unusual case. It's a projection of an un-mapped property, so I would not expect it to be tracked. However, it's actually the same type as the query root, and what's more it's even the same instance as returned by the query. But also imagine a slight variation of this where the projected object is the same type, but is a different instance than returned from the query--for example: public class Entity
{
public int EntityId { get; set; }
[NotMapped] public Entity This => this.Clone();
} |
@ajcvickers I agree with you that this is a very unusual case. Please note however, that this is just a minimal reproduction example. I was surprised that such a projection is possible at all because in my real project I turned off client evaluation. The thing that worries me most is the fact that EF Core created and exposed an entity without change tracking, even though change tracking was not explicitly disabled. According to the documentation entities should be included in change tracking even when returned as a result of a projection. |
In 3.0, unmapped property causes client eval. It will happen because it is in projection. The entity we materialize from database will be tracked. (We avoided tracking objects before client eval in 2.x but we are going away from that behavior). If your unmapped property returns object of a mapped type, it won't be tracked because tracking happens on the objects we materialize from database regardless of what comes out as result. |
All the explanations in our documentation are trying to hit the sweet spot between simplicity and accuracy to enable the user to build a mental model of how things work without reading half of the EF Core codebase. Unfortunately, there are many things you can express in a LINQ query in which it isn't clear what the outcome is going to be. In the past, it has been hard to distill simple and consistent principles to guide what the behavior should be in those cases. Projecting an un-mapped property is one example of such scenario in which tracking could go either way. Another example is explicitly creating an entity type in the projection, by either invoking the constructor or invoking a client method that returns an instance. As @smitpatel mentioned, in the new LINQ implementation in EF Core 3.0 we are trying to align to a new set of principles that can help us make these decisions. Those principles are our best effort based on many years of experience from EF and LINQ to SQL. One of the principles is that the projection is split into what can be pushed down to the server and what needs to be evaluated on the client. EF Core will materialize any entities returned by the server query and track them, and then it will invoke the client-side part of the projection before returning the results. Some of this design is explained at #12795 (comment). An un-mapped property like this is completely opaque to EF Core and has to be evaluated on the client. Tracking is completely oblivious to anything that happens in the client-side projection. Consistent with this, in 3.0 we have also decided to not track an entity that is constructed explicitly or returned by a client method in the projection. As @smitpatel already explained, for this particular query, in 3.0 the entity will be tracked because we will materialize it before we project the un-mapped property on the client, but not because it is an entity type reachable in the final results. We can definitively update the documentation to reflect the 3.0 design, but unfortunately the explanation would be much more complicated if we also want to also describe the 2.x behavior. |
It sounds very reasonable that each entity which gets materialized by EF Core will also be tracked for changes in 3.0. I assumed that 2.x already behaves like that. Therefore I created this issue. I am glad to hear that the issue will be resolved in 3.0. Just to be sure: In 3.0 property A will be tracked, whereas property B will be not. Is this correct? dbContext.Entities.Select(e => { A = e.This, B = new Entity() }) |
@oliverhanappi in 3.0 for that query, B should not be tracked. |
Discussed in triage and we are happy with the 3.0 behavior. |
When selecting a not mapped property, the entity is not added to the change tracker, even though the entity can be accessed and modified.
Steps to reproduce
Further technical details
EF Core version: 2.1.11 and 2.2.4
Database Provider: Microsoft.EntityFrameworkCore.Sqlite
The text was updated successfully, but these errors were encountered: