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:
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.
An obvious solution would be to configure all backwards references via OwnedBy() and a backreference Parent on each ValueObject. The reason I would not want to do this is that the general code architecture, from ddd perspective (i think), does not see value objects as actual entities - introducing all possible backreferences would kind of violate this idea of an owned type, requiring a large code and migration change only for a change of an implementation detail (the UpdatedDate tracking). Nevertheless, if this is the "recommended" way, I would consider going with it.
The alternative I thought about is to utilize the structure of an EntityEntry which contains information about the (shadowed backreferencing) primary key and the principal entity type - although I did not find a direct way to access the owning parent (principal). The best I came up with looks something like this (this is a DbContext):
// for some entry in ChangeTracker.Entries():
if (entry.Metadata.IsOwned())
{
var ownership = entry.Metadata.FindOwnership();
var foreignKeyValue = Entry(entry.Entity).Property(ownership.Properties.First().Name).CurrentValue;
var owningEntity = Find(ownership.PrincipalEntityType.ClrType, foreignKeyValue) as Entity;
owningEntity.SetUpdatedDateUtc();
}
Is there an easier, and especially faster way to do this? This still requires an id lookup (although it should be fast given we are searching by an indexed primary key).
Sorry for the lengthy text, I hope my question is somewhat clear.
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 typeB
: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 statusUnchanged
and B the statusAdded
.Because of that, the following method was introduced:
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 callsDetectChanges
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.
OwnedBy()
and a backreferenceParent
on each ValueObject. The reason I would not want to do this is that the general code architecture, from ddd perspective (i think), does not see value objects as actual entities - introducing all possible backreferences would kind of violate this idea of an owned type, requiring a large code and migration change only for a change of an implementation detail (the UpdatedDate tracking). Nevertheless, if this is the "recommended" way, I would consider going with it.this
is a DbContext):Is there an easier, and especially faster way to do this? This still requires an id lookup (although it should be fast given we are searching by an indexed primary key).
Sorry for the lengthy text, I hope my question is somewhat clear.