不能“;添加或更新“;实体,因为Primery密钥无法更改

本文关键字:密钥 Primery 添加 更新 实体 不能 因为 | 更新日期: 2023-09-27 18:19:52

我正在实现一个导入例程,用户将特定格式的字符串粘贴到输入字段中,然后将其转换为实体,然后放入数据库。

该算法检查实体是否已经存在,并尝试更新它或将它插入数据库。插入工作正常-更新失败。

//considered existing if Name and owning user match.
if (db.Captains.Any(cpt => cpt.Name == captain.Name && cpt.User.Id == UserId))
{
    var captainToUpdate = db.Captains.Where(cpt => cpt.Name == captain.Name && cpt.User.Id == UserId).SingleOrDefault();
    db.Entry(captainToUpdate).CurrentValues.SetValues(captain);
    db.Entry(captainToUpdate).State = EntityState.Modified;
    await db.SaveChangesAsync();
 }

手头的问题是,这样写,它也会尝试更新主键(captain Id为0,而captainToUpdate Id已设置),这会导致异常The property 'Id' is part of the object's key information and cannot be modified.

我需要更改什么,以便正确更新enttiy。如果可以避免的话,我不想手动更新每个属性,因为Captain表包含30多列。

不能“;添加或更新“;实体,因为Primery密钥无法更改

您可以做的是首先将captainToUpdate:的Id设置为与captainToUpdate的Id相同

captain.Id = captainToUpdate.Id;
db.Entry(captainToUpdate).CurrentValues.SetValues(captain);
await db.SaveChangesAsync();

我不会使用实体Captain将数据传输到UI,而是使用一个DTO对象,该对象具有您想要复制的所有属性,而不是更多属性您可以从任何对象复制值将复制所有匹配的属性,captainToUpdate中的所有其他属性将不受影响。

试试这样的东西?

var captainToUpdate = db.Captains.FirstOrDefault(cpt => cpt.Name == captain.Name &&     cpt.User.Id == UserId);
if(captainToUpdate != null){//Update captain Here
    captainToUpdate.Update(captain);        
}else{//Create captain here
    db.Captains.Add(captain);
}
db.Savechanges();

我也遇到了同样的问题,并通过扩展方法和反射解决了它,当然,最好创建一个独立的类,并对重新感染进行一些计算,但性能在我的任务中并不重要。

public static class EnitityFrameworkHelper
    {
        public static void SetValuesByReflection(this DbPropertyValues propertyValues, object o, IEnumerable<string> properties = null)
        {
            var reflProperties = o.GetType().GetProperties();
            var prop = properties ?? propertyValues.PropertyNames;
            foreach (var p in prop)
            {
                var refp = reflProperties.First(x => x.Name == p);
                var v= refp.GetValue(o);
                propertyValues[p] = v;
            }
        }
    }

下面是如何使用的例子

 var entry = ctx.Entry(accSet);
 entry.CurrentValues.SetValuesByReflection(eParameters, entry.CurrentValues.PropertyNames.Except(new [] { "ID"}));

还要小心要更新的对象中的外键,可能您也想排除它们。