实体类型“xTestType”的实例无法被跟踪,因为已经有另一个具有相同键的此类型实例正在被跟踪。

3

我正在尝试从表中删除多行数据。但在第一次迭代后,它会给出以下错误。我可以看到所有 xTestType 对象上的主键 Id 都为 0。这可能是问题所在。为什么它总是给出 Id0

foreach (var temp in oldxDetails.TestTypes)
{
  if (deleteTestTypes.Contains(input.Id))
  {
    var xTestType = new xTestType
    {
      xId = xId,
      TestTypeMasterId = temp.Id
    };

    await _xTestRepository.DeleteAsync(xTestType);
  }
}

异常:

无法跟踪实体类型“xTestType”的实例,因为已经有另一个具有相同键的此类型实例正在被跟踪。当添加新实体时,对于大多数键类型,如果未设置键(即如果键属性分配了其类型的默认值),将创建唯一的临时键值。如果您明确为新实体设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值发生冲突。在附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。


你可能需要附加到xTextType实体,因为它已经被跟踪,然后你就可以成功删除它了。但是,我不明白为什么你在已经有引用的情况下(正如错误消息所示),还要实例化一个新的xTestType()。 - Digvijay
错误信息已经很明显了。输入是由上下文跟踪的(因此附加到上下文)。如果您创建另一个具有相同ID值的条目并尝试删除它,则必须将其附加到上下文。为什么ID值始终为0很难说,这与此错误无关。可能您使用了identity insert保存了该值,或者从未将该值保存到数据库中,但在本地DbContext实例中进行了所有更改。 - DevilSuichiro
你在 new xTestType() 中没有设置 Id 吗? - aaron
你有什么方法吗,@aaron? - Vivek Nuna
那不是推荐的方式。 - Vivek Nuna
显示剩余2条评论
2个回答

7
当你从数据库中获取数据并对其进行迭代时,例如:
var dataObject = await dbContext.Table.where(x=>x.UserId == model.UserId).TolistAsync();
foreach(var item in dataObject)
{ 

}

不要创建另一个对象,直接将获取的对象传递给Delete或用它来更新,因为DbContext正在跟踪它已经获取的对象,而不是您创建的对象。例如:
//Wrong code
var dataObject = await dbContext.Table.where(x=>x.UserId == model.UserId).TolistAsync();
foreach(var item in dataObject)
{ 
   var x=new DataObject()
   {
      x=item.Id
   };
   dbContext.Table.Remove(x);
}

你必须将最初获取的实例传递给Remove()方法,参见:

var dataObject = await dbContext.Table.where(x=>x.UserId == model.UserId).TolistAsync();
foreach(var item in dataObject)
{ 
    dbContext.Table.Remove(item);
}

6
问题产生的原因是Entity Framework在获取到所有实体中的xTestType时进行了追踪。有两种方法可以解决这个问题。
方法1:
DbContext.Entry(xTestTypeOld).State = EntityState.Deleted;  // where xTestTypeOldis record from which you are taking xId

方法二:

DbContext.Entry(xTestTypeOld).State = EntityState.Detached;
DbContext.Entry(xTestType).State = EntityState.Deleted;

我认为第一个方法是最好的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接