![](/img/trans.png)
[英]EF: The instance of entity type X cannot be tracked because another instance of this type with the same key is already being tracked
[英]The instance of entity type 'SalesOrder' cannot be tracked because another instance of this type with the same key is already being tracked
我正在使用.net core。
我的目标:我希望能够在
Creating
之后立即Edit
SalesOrder。
现在,我可以创建和编辑了。 但是它抛出一个错误
无法跟踪实体类型“ SalesOrder”的实例,因为已经跟踪了具有相同键的该类型的另一个实例。 添加新实体时,对于大多数键类型,如果未设置任何键(即,如果为键属性分配了其类型的默认值),则将创建唯一的临时键值。 如果您为新实体明确设置键值,请确保它们不与现有实体或为其他新实体生成的临时值冲突。 附加现有实体时,请确保仅将一个具有给定键值的实体实例附加到上下文。
当我尝试创建后立即进行编辑时。
我的Save()函数:
public class SalesOrdersController : Controller
{
private readonly ApplicationDbContext _dbContext;
public SalesOrdersController(ApplicationDbContext dbContext){
_dbContext = dbContext;
}
// ...other Controller actions
public JsonResult Save([FromBody]SalesOrderViewModel salesOrderViewModel)
{
SalesOrder salesOrder = new SalesOrder();
salesOrder.document_id = salesOrderViewModel.document_id;
salesOrder.customer = salesOrderViewModel.customer;
salesOrder.document_status_id = salesOrderViewModel.document_status_id;
...
salesOrder.object_state = salesOrderViewModel.object_state;
_dbContext.Entry(salesOrder).State = Helpers.ConvertState(salesOrder.object_state);
_dbContext.SaveChanges();
salesOrderViewModel.document_id = salesOrder.document_id;
salesOrderViewModel.object_state = ObjectState.Unchanged;
return Json(new { salesOrderViewModel });
}
}
以及根据请求更新状态的功能:
public static EntityState ConvertState(ObjectState objectState){
switch (objectState){
case ObjectState.Added:
return EntityState.Added;
case ObjectState.Modified:
return EntityState.Modified;
case ObjectState.Deleted:
return EntityState.Deleted;
default:
return EntityState.Unchanged;
}
}
我知道在创建后刷新实体状态是一个问题。 我该如何解决该错误?
您说您了解问题...因此解决方案是从数据库中获取原始实体并直接更新其属性,然后再对其进行更新。 我的意思是你需要避免打电话
context.Update(entity);
其中实体是模型中的对象。
因此,一种解决方案将是类似于以下内容的解决方案,我同意这可能不是解决问题的最佳方法。
假设您使用的是通用存储库(这比非通用存储库难,因为您事先不知道字段)
public void Edit(TBusinessObject entity)
{
var originalEntity = context.Set<TBusinessObject>().AsNoTracking().FirstOrDefault(r => r.Id.Equals(entity.Id));
EntityEntry<TBusinessObject> original = context.Entry(originalEntity);
EntityEntry<TBusinessObject> client = context.Entry(entity);
foreach (var property in original.OriginalValues.Properties)
{
var dbMember = original.Member(property.Name);
var clientMember = client.Member(property.Name);
if(!property.IsPrimaryKey() && dbMember.CurrentValue != clientMember.CurrentValue && clientMember.CurrentValue!= null)
{
dbMember.CurrentValue = clientMember.CurrentValue;
dbMember.IsModified = true;
}
}
context.Update(originalEntity);
context.SaveChanges(true);
}
同样,可以优化此代码,如果它不是通用存储库(您可以在其中知道字段的名称和类型),则可以更简单。
更新1:我发现EF.Core尚未完全具备EF6支持的所有功能。 但是,它还是某种程度上倾向于现代开发实践。您发布的示例全部关于使用EF.Core来实现传统的存储库思想。 如果切换到使用UnitOfWork或CQRS,您将不会遇到这些问题,更新和CRUS之类的更改通常将变得前所未有地流畅。 我将一个对象传递给上下文,并且上下文本身可以弄清楚它属于哪个表以及如何处理它。 因此,我建议更改选择使用EF.Core的方式
试试这个最简单的实现:
public void Commit()
{
using (var context = new ApplicationDbContext())
{
context.UpdateRange(Changed);
context.AddRange(Added);
context.RemoveRange(Deleted);
context.SaveChanges();
ClearAllChanges();
}
}
“更改,添加,删除”只是列出您可能考虑使用AsynchronousBags的列表
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.