C# 如何在实体框架中处理过时的缓存?

C# 如何在实体框架中处理过时的缓存?,c#,entity-framework,asp.net-web-api,C#,Entity Framework,Asp.net Web Api,我从实体框架中得到了非常奇怪的行为。我正在编写一个WebApi应用程序,以便断开/分离从浏览器获取的对象。我得到的数据是事务性的,因此它与数据库中的任何给定表都不匹配。我必须进行大量的查找和数据操作,以获得数据库的实际更新 我似乎遇到的问题是,在查询数据时,我正在填充跟踪的更改缓存。这对我来说似乎不是问题,因为数据的真正来源应该是数据库。当我最终进行数据更改并调用SaveChanges时,会出现约束错误。这是我的步骤 查询数据 创建要插入的行 将行与数据库进行比较,并对数据库进行更改 在查看Ct

我从实体框架中得到了非常奇怪的行为。我正在编写一个WebApi应用程序,以便断开/分离从浏览器获取的对象。我得到的数据是事务性的,因此它与数据库中的任何给定表都不匹配。我必须进行大量的查找和数据操作,以获得数据库的实际更新

我似乎遇到的问题是,在查询数据时,我正在填充跟踪的更改缓存。这对我来说似乎不是问题,因为数据的真正来源应该是数据库。当我最终进行数据更改并调用SaveChanges时,会出现约束错误。这是我的步骤

  • 查询数据
  • 创建要插入的行
  • 将行与数据库进行比较,并对数据库进行更改
  • 在查看Ctx.ChangeTracker.Entries()中的数据后,我发现要删除的条目在应该删除时被标记为已修改。我解决这个问题的方法是为第3步创建一个新的上下文。它神奇地开始工作。我原以为就是这样,但在我的测试用例中,我最后读取了数据库,以验证我的事务是否正确写入。我得到了一个应该被删除的额外行。事实上,当直接检查数据库时。再次使用一个新的上下文来执行上次读取修复了问题

    我只是假设默认的缓存设置只用于跟踪更改,而不是加速查询

    如果我尝试在查询中使用AsNoTracking,我也会遇到麻烦,因为如果我尝试删除这样查询的行,我会得到一个错误。在我的代码中,我不知道是否要删除或修改,直到以后。有没有办法清除缓存,这样我就不需要创建新的上下文

    有没有更好的方法来处理这些问题

    编辑:

    在某种程度上,AsNoTracking会起作用。我仍然发现自己实例化了更多的DbContext副本以防止出错。必须删除多对一实体,否则会触发空外键错误

    var details = oldInvoice.details.ToList();
    
    Context.Entry(oldInvoice).State = EntityState.Unchanged;
    Context.Entry(oldInvoice).State = EntityState.Deleted;
    details.ForEach(a => Context.Entry(a).State = EntityState.Deleted);
    

    实体框架提供了一个异常
    DbUpdateConcurrencyException
    ,您可以在调用
    SaveChanges()
    时捕捉到该异常。您可以循环处理错误,如下所示:

    catch (DbUpdateConcurrencyException ex)
        {
            saveFailed = true;
    
            // Get the current entity values and the values in the database
            var entry = ex.Entries.Single();
            var currentValues = entry.CurrentValues;
            var databaseValues = entry.GetDatabaseValues();
    
            // Choose an initial set of resolved values. In this case we
            // make the default be the values currently in the database.
            var resolvedValues = databaseValues.Clone();
    
            // Have the user choose what the resolved values should be
            HaveUserResolveConcurrency(currentValues, databaseValues,
                                       resolvedValues);
    
            // Update the original values with the database values and
            // the current values with whatever the user choose.
            entry.OriginalValues.SetValues(databaseValues);
            entry.CurrentValues.SetValues(resolvedValues);
        }
    
    } while (saveFailed);
    

    此外,您的更新代码听起来也很可疑。通常,当您通过WebApi或其他机制将数据传递给客户机时,返回的数据没有跟踪数据,因此您应该检查它是否存在,并将其重新附加到上下文中,并将其状态更改为
    EntityState。在调用
    SaveChanges()之前修改
    如果存在

    将上下文保留很长一段时间是个坏主意,因为当跟踪图中包含大量实体时,跟踪图的性能不好。我的建议是不要在请求之间重复使用上下文。这也可以避免任何并发的更新问题,谢谢你的回答。关于丢失的跟踪数据,您是正确的。所以我完全按照你在下面描述的做。除了前面的查询弄乱了跟踪数据。