自定义EF Core保存方法中的InvalidOperationException

时间:2017-05-15 06:53:19

标签: c# entity-framework entity-framework-core

我正在为EF Core中的框架编写自定义保存通用方法。我们的想法是拥有一种可以进行部分更新的方法。

代码是这样的:

public IEnumerable<T> UpdateEntitiesByProperties(IEnumerable<UpdateByPropertiesData<T>> entitiesAndProperties)
{
   List<T> entities = new List<T>();

   foreach (var entityAndProperties in entitiesAndProperties)
   {
        T contextEntity = this.context.Find<T>(entityAndProperties.Entity.Id);
        EntityEntry<T> changeTrackerEntityEntry = this.context.Entry(contextEntity);

        changeTrackerEntityEntry.CurrentValues.SetValues(entityAndProperties.Entity);

        foreach (var property in changeTrackerEntityEntry.Properties.Where(p => !p.Metadata.IsConcurrencyToken))
        {
            property.IsModified = entityAndProperties.UpdatedProperties.Contains(property.Metadata.Name);
        }

     entities.Add(contextEntity);
   }

   return entities;
}

如果我将代码更改为此代码,它可以正常工作:

public IEnumerable<T> UpdateEntitiesByProperties(IEnumerable<UpdateByPropertiesData<T>> entitiesAndProperties)
{
   List<T> entities = new List<T>();

   foreach (var entityAndProperties in entitiesAndProperties)
   {
        T contextEntity = this.context.Find<T>(entityAndProperties.Entity.Id);
        EntityEntry<T> changeTrackerEntityEntry = this.context.Entry(contextEntity);

        changeTrackerEntityEntry.CurrentValues.SetValues(entityAndProperties.Entity);

        foreach (var property in changeTrackerEntityEntry.Properties.Where(p => !p.Metadata.IsConcurrencyToken))
        {
            if(entityAndProperties.UpdatedProperties.Contains(property.Metadata.Name)
            {
                property.CurrentValue = typeof(T).GetTypeInfo().GetDeclaredProperty(property.Metadata.Name).GetValue(entityAndProperties.Entity);  
            }
        }

     entities.Add(contextEntity);
   }

   return entities;
}

该方法使用简单实体,但在entitiesAndProperties中的实体不包含必填字段时抛出InvalidOperationException。

例外文字是:

  

实体类型“User”上的属性“Name”被标记为null,但由于该属性被标记为必需,因此无法保存。

这应该不是问题,因为实体已经存在于具有必填字段值的数据库中,contextEntity反映了这一点,但似乎CurrentValues.SetValues覆盖了这一点。

1 个答案:

答案 0 :(得分:0)

虽然我同意@Gert Arnold评论说你应该避免CurrentValues.SetValues在这种情况下,代码看起来很合法,所以我认为这是当前的EF Core实现错误。

这是AFAIK唯一不会更改目标对象中属性CurrentValue的情况,但在内部将其标记为无效。通常设置IsModified = falseCurrentValue = OriginalValue会恢复属性值,但在这种情况下不会(因为值相同),这没关系,但问题是它也没有删除&#34;无效标记&#34;,我认为这是错误。

我建议您使用当前的解决方法并将问题发布到问题跟踪器。