简体   繁体   English

无法跟踪实体类型“ SalesOrder”的实例,因为已经跟踪了具有相同键的该类型的另一个实例

[英]The instance of entity type 'SalesOrder' cannot be tracked because another instance of this type with the same key is already being tracked

I am using .net core. 我正在使用.net core。

My Goal: I want to be able Edit a SalesOrder just after Creating . 我的目标:我希望能够在Creating之后立即Edit SalesOrder。

Right now I am able to Create and Edit. 现在,我可以创建和编辑了。 But it is throwing an error 但是它抛出一个错误

The instance of entity type 'SalesOrder' cannot be tracked because another instance of this type with the same key is already being tracked. 无法跟踪实体类型“ SalesOrder”的实例,因为已经跟踪了具有相同键的该类型的另一个实例。 When adding new entities, for most key types a unique temporary key value will be created if no key is set (ie if the key property is assigned the default value for its type). 添加新实体时,对于大多数键类型,如果未设置任何键(即,如果为键属性分配了其类型的默认值),则将创建唯一的临时键值。 If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities. 如果您为新实体明确设置键值,请确保它们不与现有实体或为其他新实体生成的临时值冲突。 When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context. 附加现有实体时,请确保仅将一个具有给定键值的实体实例附加到上下文。

When I try editing just after creating. 当我尝试创建后立即进行编辑时。

My Save() function: 我的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 });
    }
}

And a function to update states depending on the request: 以及根据请求更新状态的功能:

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

I understand that it is a problem with refreshing the entity state just after creating. 我知道在创建后刷新实体状态是一个问题。 How can I resolve that error? 我该如何解决该错误?

You said you understand the problem... so the solution is to get the original entity from the database and update its properties directly and then update it itself. 您说您了解问题...因此解决方案是从数据库中获取原始实体并直接更新其属性,然后再对其进行更新。 I mean what you need to do is to avoid calling 我的意思是你需要避免打电话

    context.Update(entity);

Where entity is the object in your model. 其中实体是模型中的对象。

So One solution would be something like the following which I agree it may not the best way of solving it. 因此,一种解决方案将是类似于以下内容的解决方案,我同意这可能不是解决问题的最佳方法。

Let's assume you are using generic repository (which is harder than non generic because you do not know the fields beforehand) 假设您使用的是通用存储库(这比非通用存储库难,因为您事先不知道字段)

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

Again, This code could be optimized and it would be way simpler if it was not a generic repository, where you know the names and the types of the fields. 同样,可以优化此代码,如果它不是通用存储库(您可以在其中知道字段的名称和类型),则可以更简单。

Update 1: I found out that EF.Core although not yet fully fledged with all the features that were supported by EF6. 更新1:我发现EF.Core尚未完全具备EF6支持的所有功能。 Yet it is somehow leaned towards the modern development practices.. The example that you posted was all about using EF.Core to implement the traditional repository mentality. 但是,它还是某种程度上倾向于现代开发实践。您发布的示例全部关于使用EF.Core来实现传统的存储库思想。 If you switch to use UnitOfWork or CQRS you will not face these problems, changes like updates and CRUS in general will be smooth like never before. 如果切换到使用UnitOfWork或CQRS,您将不会遇到这些问题,更新和CRUS之类的更改通常将变得前所未有地流畅。 I am passing an object to the context, and the context itself is able to figure out to what table it belongs and how to handle it. 我将一个对象传递给上下文,并且上下文本身可以弄清楚它属于哪个表以及如何处理它。 Therefore I recommend changing the way you choose to utilize EF.Core 因此,我建议更改选择使用EF.Core的方式

Try this simplest implementation: 试试这个最简单的实现:

public void Commit()
{
    using (var context = new ApplicationDbContext())
    {
            context.UpdateRange(Changed);
            context.AddRange(Added);
            context.RemoveRange(Deleted);

            context.SaveChanges();
            ClearAllChanges();
    }
}

Where "Changed, Added, Deleted" are just lists where you might consider AsynchronousBags “更改,添加,删除”只是列出您可能考虑使用AsynchronousBags的列表

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 EF:无法跟踪实体类型X的实例,因为已经跟踪了具有相同密钥的此类型的另一个实例 - 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 … cannot be tracked because another instance of this type with the same key is already being tracked 无法跟踪实体类型“xTestType”的实例,因为已跟踪具有相同键的此类型的另一个实例? - The instance of entity type 'xTestType' cannot be tracked because another instance of this type with the same key is already being tracked? 无法跟踪实体类型“ TestType”的实例,因为已经跟踪了具有相同键的该类型的另一个实例 - The instance of entity type 'TestType' cannot be tracked because another instance of this type with the same key is already being tracked 无法跟踪实体类型“Entity”的实例,因为已跟踪另一个具有与 {'Id'} 相同键值的实例 - The instance of entity type 'Entity' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型的实例,因为已在跟踪具有相同键的该类型的另一个实例 - The instance of entity type cannot be tracked because another instance of this type with the same key is already being tracked 无法跟踪实体类型的实例,因为已在跟踪具有相同键值的另一个实例 - The instance of entity type cannot be tracked because another instance with the same key value is already being tracked 无法跟踪实体类型“书签”的实例,因为已经在跟踪具有相同键值 {'ID'} 的另一个实例 - The instance of entity type 'Bookmark' cannot be tracked because another instance with the same key value for {'ID'} is already being tracked 无法跟踪实体类型“Item”的实例,因为已跟踪另一个具有与 {'Id'} 相同键值的实例 - The instance of entity type 'Item' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型的实例,因为已跟踪具有相同键值的另一个实例 - The instance of entity type cannot be tracked because another instance with the same key value for is already being tracked
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM