简体   繁体   English

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

[英]InvalidOperationException in a custom EF Core save method

I am writing a custom save generic method for our framework in EF Core.我正在为 EF Core 中的框架编写自定义保存通用方法。 The idea is to have a method that can make partial updates.这个想法是有一个可以进行部分更新的方法。

The code is like this:代码是这样的:

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

If I change the code to this, it works correctly:如果我将代码更改为此,它可以正常工作:

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

The method is working with simple entities but throws an InvalidOperationException when the entity in entitiesAndProperties does not contain a required field.该方法适用于简单实体,但当 entityAndProperties 中的实体不包含必填字段时会引发 InvalidOperationException。

The exception text is:异常文本是:

The property 'Name' on entity type 'User' is marked as null, but this cannot be saved because the property is marked as required.实体类型“用户”上的属性“名称”被标记为空,但无法保存,因为该属性被标记为必需。

It should not be a problem, because the entity already exists in database with the required field value, contextEntity reflects that, but seems the CurrentValues.SetValues overrides this.这应该不是问题,因为实体已经存在于具有所需字段值的数据库中, contextEntity反映了这一点,但似乎CurrentValues.SetValues覆盖了这一点。

Although I agree with @Gert Arnold comment that you should probably avoid CurrentValues.SetValues in such scenario, the code looks to me pretty legal, so I'm considering this to be a current EF Core implementation bug.尽管我同意 @Gert Arnold 的评论,即在这种情况下您可能应该避免使用CurrentValues.SetValues ,但代码在我看来非常合法,因此我认为这是当前的 EF Core 实现错误。

It's the only case AFAIK which doesn't change the CurrentValue of the property in the target object, but marks it somewhere internally as invalid.这是 AFAIK 不更改目标对象中属性的CurrentValue的唯一情况,但在内部某处将其标记为无效。 Normally setting IsModified = false or CurrentValue = OriginalValue restores the property value, but not in this case (because the value is the same), which is ok, but the problem is that it also doesn't remove the "invalid mark", which I think is the bug.通常设置IsModified = falseCurrentValue = OriginalValue恢复属性值,但在这种情况下(因为值相同),这没关系,但问题是它也没有去除“无效标记”,这我认为是错误。

I would suggest using your current workaround and posting the issue to their issue tracker.我建议使用您当前的解决方法并将问题发布到他们的问题跟踪器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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