简体   繁体   中英

EntityEntry.Property() throws InvalidOperationException when property does exist

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM