I am working on a change analyzer for Entity Framework and have one small problem left.
I need to get the Property (PropertyInfo) of the parent in a relation (1-1, 1-n, n-n).
Right now I can see the relation, the parent and the related entries, but I cannot seem to get the actual property of the object. The problem as I see it is that the relation knows about the keys, which are PKs and FKs and not the property that was responsible for the relation in the first place. In my solution now, I use the EntitySet name from the related entity, but that just isn’t good enough.
Here is the code that resolves the relations. I’ve left out the entity objects as well as the non relational analyzing parts. The IHaveLogEntries interface is to be implemented on Entities that want to be analyzed.
Also, this code runs in DbContext.SaveChanges()
this.ChangeTracker.DetectChanges();
var objectContext = ((IObjectContextAdapter)this).ObjectContext;
var entityEntries = objectContext.ObjectStateManager
.GetObjectStateEntries(EntityState.Unchanged | EntityState.Modified | EntityState.Added)
.ToList();
var relationEntries = objectContext.ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Deleted)
.ToList();
var q = from relationEntry in relationEntries
from entityEntry in entityEntries
where relationEntry.IsRelationshipForKey(entityEntry.EntityKey)
where !(entityEntry.Entity is IHaveLogEntries)
let otherEndKey = relationEntry.OtherEndKey(entityEntry.EntityKey)
let logEntryEntity = entityEntries
.Where(e => e.EntityKey == otherEndKey)
.Select(se => se.Entity)
.Cast<IHaveLogEntries>()
.Single()
let combined = new
{
RelationEntry = relationEntry,
EntityEntry = entityEntry,
LogEntryEntity = logEntryEntity
}
group combined by
new { combined.LogEntryEntity, combined.EntityEntry.EntitySet.Name }
into combinedGroup
let added = combinedGroup
.Where(c => c.RelationEntry.State == EntityState.Added)
.Select(c => c.EntityEntry.Entity.ToString())
let deleted = combinedGroup
.Where(c => c.RelationEntry.State == EntityState.Deleted)
.Select(c => c.EntityEntry.Entity.ToString())
select new
{
combinedGroup.Key.LogEntryEntity,
Field = combinedGroup.Key.Name,
Operation = Operation.Modified,
FromValue = (object)string.Join(",", deleted.ToArray()),
ToValue = (object)string.Join(",", added.ToArray())
};
var l = q.ToList();
The main problem is where I group the result, where I use combined.EntityEntry.EntitySet.Name. I would like to figure out the name of the property on the IHaveLogEntries entity instead if that is possible. That entity would be the combined.LogEntryEntity in this case.
Thankful for your input.
I’ve solved it now using the
ObjectStateEntry.EntitySetproperty of the relationEntry that I had. With that, I can see the name of the relation like this Entity_Property and I simply do a string extraction of the property name there which I then use to get thePropertyInfoobject from the Entity.Then I’ve added am Attribute so that I can decorate properties with better names if necessary.
This is what I added somewhere in the middle there:
I then use the name to group on instead:
It does seem to work so far, even though I would like to know if anyone has a better idea. The string management feels a bit dodgy.