我正在为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
覆盖了这一点。
答案 0 :(得分:0)
虽然我同意@Gert Arnold评论说你应该避免CurrentValues.SetValues
在这种情况下,代码看起来很合法,所以我认为这是当前的EF Core实现错误。
这是AFAIK唯一不会更改目标对象中属性CurrentValue
的情况,但在内部将其标记为无效。通常设置IsModified = false
或CurrentValue = OriginalValue
会恢复属性值,但在这种情况下不会(因为值相同),这没关系,但问题是它也没有删除&#34;无效标记&#34;,我认为这是错误。
我建议您使用当前的解决方法并将问题发布到问题跟踪器。