不能"添加或更新或#34;实体因为主键无法更改

时间:2014-08-28 07:53:59

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

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

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

//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列。

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

您可以做的是首先将队长的Id设置为与captainToUpdate的Id相同。在这种情况下使用:

db.Entry(captainToUpdate).CurrentValues.SetValues(captain);

会奏效。

答案 2 :(得分:1)

尝试这样的事情?

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();

答案 3 :(得分:0)

我遇到了同样的问题并通过扩展方法和反射解决了这个问题,当然最好创建一个带有一些缓存的独立类来进行重复处理,但性能在我的任务中并不重要。

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

另外要注意要更新的对象中的外键,可能还要排除它们。