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

How to access the principal entity given an owned entity? #29848

Open nstdspace opened 1 year ago

nstdspace commented 1 year ago

To avoid running into an A-B Problem I will try to summarize where the question is coming from.

In our application we are heaviliy using owned entitiy types for ddd-like value objects. Also, to track the CreatedDate and UpdatedDate of entities we have some basic logic in our override of SaveChanges which utilizes the context's ChangeTracker to get changed entities and update the respective values.

Now, suppose we have some entity A which owns the type B:

// entity classes
class A : Entity {
    public B B { get; private set; }
}

class B : ValueObject {
    // ...
}

// configuration
modelBuilder.Entity<A>().OwnsOne(a => a.B);

If, during a transaction, only A.B is changed (via A.B = new B()), the change tracker contains an entry for both entities, A and B, but the A-entry has the status Unchanged and B the status Added.

Because of that, the following method was introduced:

private bool IsValueObjectModified(EntityEntry entity)
{
    return entity.Navigations.Any(navigation =>
        navigation.CurrentValue is ValueObject
        && ((ReferenceEntry) navigation).TargetEntry.State == EntityState.Added
    );
}

The idea was to check all owned dependencies of all tracked entities to find out which of those have a modified value object, to then change to UpdatedDate of such an entity. Now, some cases arose, where a transaction loaded a huge amount of entities into the ChangeTracker (almost all unchanged) and where this method leads to an unacceptable performance hit - profiling the application seems to point out the access entity.Navigation as the source of the latter since it calls DetectChanges every time.

I think the easiest solution to this problem is to access the parent entity of a modified owned entity. The question is what would be the best way for that.

Sorry for the lengthy text, I hope my question is somewhat clear.

ajcvickers commented 1 year ago

@nstdspace I can't think of any better way to do this than you already have, but I agree it would be good to have something built-in.