-
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
Static entities and cannot be tracked because another instance with the key value '{Id: }' is already being tracked. #29332
Comments
@pantonis In EF7, you can use an public class MyDbContext : DbContext
{
private static readonly IgnoringIdentityResolutionInterceptor IgnoringIdentityResolutionInterceptor = new();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var connectionString = "server=127.0.0.1;port=3306;database=EfCoreDDD;uid=username;pwd=password;";
optionsBuilder
.AddInterceptors(IgnoringIdentityResolutionInterceptor)
.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString));
} |
Thanks for your reply. I have the following questions:
|
|
way too much complexity? can you explain what is the complexity here? |
The whole enum pattern with static values. But this doesn't really matter--it's just my opinion. |
They are values that never ever change. This is just a sample of my code. Have lots of those. Save a lot of calls to database, plus they are easier to work with when you work with DDD. |
Fair enough. |
Apart from this It is still not clear to me why EF Core change tracker doesn't identify those. |
Because nobody ever wrote code to do it until EF7. It's very easy to shoot yourself in the foot doing this kind of thing. The only time it's really safe is when the referenced entity type is immutable. |
They are "immutable" Didn't add private setters in the example. Although they can be modified by adding extra modifier methods this is not the purpose of their use. In any case apart from the Interceptor workaround and the db call, is there any other way of overcoming this issue I experience? |
And how would you resolve this scenario instead of using static entities? |
The core issue is that your database query is materializing instances of |
You would need to perform identity resolution manually before attaching instances. |
I can't do that since I have to check if the AccountStatus of the account is already Active first. I just used a simple scenario. In my app there is much more complicated business logic that we need the related entity loaded to check against |
Then as @ajcvickers mentioned you have to perform identity resolution yourself (so you don't try to attach different instance with same key) through interceptor or outside of interceptor. |
thanks for the reply. Materialization interceptor sounds a good idea. Is this something that supported on EF7 only? |
Just to emphasize @pantonis ' approach, I also use the "enum pattern with static values" approach. It is a well-known approach and is advocated on Pluralsight by Vladimir Khorikov |
@johannbrink once again EF Core overcomplicates things unfortunately. For something so simple. Which is an antipattern the same way that TPT and TPC is an antipattern. No words honestly. |
Am I missing something here? Microsoft provides documentation on the enumeration pattern here: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/enumeration-classes-over-enum-types So is EF Core capable of working with domain models that use enumeration classes without using this undocumented IgnoringIdentityResolutionInterceptor override? |
@johannbrink Nice finding. I was quite surprised to see that they have an example after @ajcvickers stated that is an anti-pattern. Will try to give it a shot and let you know. |
@ajcvickers any further thought after the link that I shared to the Microsoft literature above? |
EF Core doesn't support tracking multiple entity instances with the same key value. If your pattern requires this, then it won't work correctly with EF Core.
As I have said multiple times in the past, including when it was written, I don't agree with a lot of that documentation. |
I guess it’s not one Microsoft then. Sounds more like your personal opinion is getting in the way. |
@ajcvickers you are missing the point. We don’t want to track multiple entities with the same key. We want to use enumeration classes for value objects. The fact that EF insists on treating any reference type navigation property as a db table in many of the abstraction layers seem to be the source of the problem. Would be nice to creating “configurations” for these types, similar to how you do for tables when doing fluent configuration, just so that we can opt into the interceptor per type instead of globally for the whole dbcontext. |
@johannbrink See #9906 for value objects. However, the enum type shown in the original code is mapped to a table and each enum object has its own Id. So it's not a value object. |
@ajcvickers, I've gone and looked at it again, and think my issue was slightly different. Even though it is still related to value objects. I've logged a separate issue here: #29405 |
Adding 2 entities with the same tracked static value object also causes an exception
More info on this branch: https://github.com/johannbrink/EFCoreValueObjectPredicateExample/blob/error19/Program.cs #Output and exception
|
@ajcvickers Is there any way to mark this enum entity so that change tracker stops tracking in global level? Since these kind of entities never change.. |
@pantonis And if static entities work bad with EF Core, can someone suggest another pattern or solution? |
It does not. Issue occurs as soon as ChangeTracker updates its state and this is done before SaveChangesAsync. |
Some alternative to static entities. It's not the same, but solves some common problems. |
Not currently; if an object is returned by a tracking query, then it is tracked. Possibly, #7586 might allow this in the future. |
It would be good to have them. Don't understand why an entity needs to be tracked if it doesn't change? Is this something that can be done using interceptors in .NET 7 as you replied at the beginning of this post? |
No, but as Smit said above, you can use a materialization interceptor to choose the instance to materialize, and hence always use your static instance. |
@ajcvickers Is there any example or documentation of how to create and use a mat Interceptor? |
See this section in the EF Core 7.0 What's New page. |
Had exactly the same issue. Fixed it (at least for my application) by adding all the static entity instances to the DbContext (within the constructor) and set their state to unchanged. This way EF won't try to track them twice. |
I followed @ajcvickers suggestion and created an interceptor
|
A few questions... @pantonis -- what was the result? How did that work for you?
|
@nillkitty I don't think there is a good solution to this until #7586 is implemented. |
@nillkitty Not very good sometimes it causes issues when updating an entity that is using it. I hope they implement #7586 soon because this small yet important issue when working with DDD causes lots of unnecessary code |
I have an issue that I get when using static entities that exist in the database in my code. In a system using domain driven design we have static entities (we call them enum entities) where we have a lot of our business code attached to them. Problem is whenever we update an entity that has a related entity on of those enum entity we get the usual error
I have created a sample to demonstrate the issue. It can be found here at this repo.
AccountStatus is the enum entity in this case. When we retrieve the user and try to activate the user accounts we get this error
If we load those entities from database we don't get the error as the changetracker correctly identifies them. But whenever we are using the static instances we get this error. Since they are the same entities (same Ids) I don't understand why changetracker behaves likes this. From what I read in other ORMs this behavior is covered. Is this something that can be fixed in EF Core as well?
EF Core version: 6.0.9
Database provider: Pomelo.EntityFrameworkCore.MySql 6.0.2
Target framework: .NET 6
Operating system: Windows 10
IDE: (e.g. Visual Studio 2019 16.3) VS2022 17.3.0
The text was updated successfully, but these errors were encountered: