Reputation: 1491
Hello all I have the following classes:
public class EntityA
{
public Guid Id { get; set; }
public string Desc { get; set; }
public EntityB EntityB { get; set; }
}
public class EntityB
{
public Guid Id { get; set; }
public Guid EntityAId { get; set; }
public EntityA EntityA { get; set; }
}
And I have the following runtime code:
var a1 = new EntityA {Desc = "a1"};
var a2 = new EntityA {Desc = "a2"};
dbx.EntityAs.Add(a1);
dbx.EntityAs.Add(a2);
var b1 = new EntityB { EntityAId = a1.Id };
dbx.EntityBs.Add(b1);
dbx.SaveChanges();
b1.EntityAId = a2.Id;
dbx.SaveChanges();
I have modified codes in my DbContext.SaveChanges() method as below, trying to find which property in an entity has changed and its before and after values:
foreach (var entity in changedEntites)
{
var entityType = entity.Entity.GetType();
if (entity.State == EntityState.Modified)
{
var properties = entityType.GetProperties();
var props = new List<object>();
foreach (var prop in properties)
{
if(entityType.GetProperty(prop.Name) == null)
continue;
var pp = entityType.GetProperty(prop.Name);
if(pp.GetValue(entity.Entity) == null)
continue;
var p = entity.Property(prop.Name);
if (p.IsModified)
props.Add(new { f = prop.Name, o = p.OriginalValue, c = p.CurrentValue });
}
}
}
The problematic code is at this line:
var p = entity.Property(prop.Name);
It throws InvalidOperationException
:
The property 'EntityA' on entity type 'EntityB' could not be found.
Ensure that the property exists and has been included in the model.
My question is why even entityType.GetProperty(prop.Name)
and entityType.GetProperty(prop.Name).GetValue(entity.Entity)
is not null, entity.Property()
still not able to find the property?
I can just surround var p = entity.Property(prop.Name);
with a try-catch block and ignore the exception, but letting exceptions to keep throwing in an auditing scenario is not a good thing. It also does performance impact.
Any workaround is much appreciated. Thanks
Upvotes: 3
Views: 4290
Reputation: 205759
The problem is that Property
method supports only primitive properties while you are calling it with navigation property.
You can use ER Core metadata services accessible via EntityEntry.Metadata
property which returns IEntityType
. In your case, the FindProperty
method, although you should really use GetProperties
instead of reflection at the first place:
if (entity.Metadata.FindProperty(prop.Name) == null)
continue;
var p = entity.Property(prop.Name);
if (p.IsModified)
props.Add(new { f = prop.Name, o = p.OriginalValue, c = p.CurrentValue });
Upvotes: 11
Reputation: 8696
This because entity
is EntityEntry
. You should correctly name your variable to not get confused:
foreach (var entiry in changedEntries)
{
var entity = entiry.Entity;
var entityType = entity.GetType();
if (entity.State == EntityState.Modified)
{
var properties = entityType.GetProperties();
var props = new List<object>();
foreach (var prop in properties)
{
if(entityType.GetProperty(prop.Name) == null)
continue;
var pp = entityType.GetProperty(prop.Name);
if(pp.GetValue(entity) == null)
continue;
var p = entity.Property(prop.Name);
if (p.IsModified)
props.Add(new { f = prop.Name, o = p.OriginalValue, c = p.CurrentValue });
}
}
}
Upvotes: 0