当属性确实存在时,EntityEntry.Property() 抛出 InvalidOperationException

Opt*_*rog 2 c# entity-framework entity-framework-core .net-core asp.net-core

大家好,我有以下课程:

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; }
}
Run Code Online (Sandbox Code Playgroud)

我有以下运行时代码:

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();
Run Code Online (Sandbox Code Playgroud)

我修改了 DbContext.SaveChanges() 方法中的代码,如下所示,尝试查找实体中的哪个属性已更改及其前后值:

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 });
    }
}
}
Run Code Online (Sandbox Code Playgroud)

有问题的代码在这一行:

var p = entity.Property(prop.Name);
Run Code Online (Sandbox Code Playgroud)

它抛出InvalidOperationException:

The property 'EntityA' on entity type 'EntityB' could not be found.
Ensure that the property exists and has been included in the model.
Run Code Online (Sandbox Code Playgroud)

我的问题是,为什么连entityType.GetProperty(prop.Name)和entityType.GetProperty(prop.Name).GetValue(entity.Entity)不为空,entity.Property()依然没能找到的财产?

我可以var p = entity.Property(prop.Name);用 try-catch 块包围并忽略异常,但是让异常在审计场景中继续抛出并不是一件好事。它也会影响性能。

任何解决方法都非常感谢。谢谢

Iva*_*oev 7

问题在于,Property当您使用导航属性调用它时,该方法仅支持原始属性。

您可以使用可通过EntityEntry.Metadata返回IEntityType. 在您的情况下,该FindProperty方法虽然您应该真正使用GetProperties而不是首先使用反射:

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 });
Run Code Online (Sandbox Code Playgroud)