EntityEntry.Property() throws InvalidOperationException when property does exist

.net-core asp.net-core c# entity-framework entity-framework-core

Question

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

1
2
11/11/2016 8:19:44 AM

Accepted Answer

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 });
3
11/11/2016 11:35:03 AM

Popular Answer

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 });
        }
    }
}


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow