实体框架.First()缓存查询数据

时间:2017-12-04 16:53:12

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

根据实体框架文档,实体框架仅在使用.Find()查询数据时缓存数据。

在以下示例中,我使用.First()时缓存了查询数据:

  static void Main(string[] args)
    {
        var trxScope = new TransactionScope();
        var context = new SekhavatDBEntities();

        //the value of Balance is Zero
        var account =
            context.Accounts.First(acc => acc.Id == new Guid("79B7AAC6-AD2D-4824-907E-16ADB4C41EE1"));            
        account.Balance = 50;

        context.SaveChanges();
        trxScope.Dispose();

        var trxScope2 = new TransactionScope();
        var account2 =
            context.Accounts.First(acc => acc.Id == new Guid("79B7AAC6-AD2D-4824-907E-16ADB4C41EE1"));

        //Balance of account2 Is 50 Now!
        trxScope2.Dispose();
    }

为什么account2的余额为50?根据我的考虑,它应该是0。

提前致谢

3 个答案:

答案 0 :(得分:3)

以下是documentation的相关引用:

  

请注意,DbSet和IDbSet始终会针对数据库创建查询   并且将始终涉及到数据库的往返,即使   返回的实体已存在于上下文

中      

...

     

从数据库返回结果时,不存在的对象   在上下文中附加到上下文。 如果某个对象已在   上下文,返回现有对象(当前和原始对象)   条目中对象属性的值不会被覆盖   数据库值)。

使用交易与否是无关紧要的。相关的是:

  1. EF不会在事务回滚时将值更改回原始值(我认为它甚至不可能这样做,但无论如何)。如果您使用TransactionScopectx.Database.BeginTransaction

  2. ,则无关紧要
  3. 在您进行第二次查询时,您的帐户ID为79B7AAC6-AD2D-4824-907E-16ADB4C41EE1已被上下文跟踪。根据上述文档 - 将对数据库进行查询,但此查询的结果将被丢弃,并且不会覆盖当前跟踪的实体的值。相反,实体将按原样返回(余额等于50)。

  4. 要防止这种情况:

    1. 为单独的操作使用单独的上下文,并尽可能避免重复使用上下文。

    2. 使用AsNoTracking。这将阻止上述行为,并且将始终返回实体,因为它现在在数据库中。

    3. 使用Reload

      context.Entry(account).Reload();
      
    4. 这将查询此实体的数据库,并使用当前数据库值覆盖所有值。

答案 1 :(得分:1)

您的TransactionScope必须在您的上下文中并开始交易

如果您按照自己的方式声明了

,那么您的上下文中没有打开的事务

使用 Celso Livero等信息表示=> MSDN Page

using (var context = new SekhavatDBEntities()) 
{ 
    using (var dbContextTransaction = context.Database.BeginTransaction()) 
    { 
        var account = context.Accounts.First(acc => acc.Id == new Guid("79B7AAC6-AD2D-4824-907E-16ADB4C41EE1"));            
        account.Balance = 50;
        context.SaveChanges();

        dbContextTransaction.Rollback(); 
    } 
} 

使用其他context检查数据

using (var context = new SekhavatDBEntities()) 
{ 
    var account2 = context.Accounts.First(acc => acc.Id == new Guid("79B7AAC6-AD2D-4824-907E-16ADB4C41EE1"));
}

First()Find()不是您的交易问题。 并且像 Erk 一样说,看到在上下文中已经存在具有相同键的实体

数据在您的context中缓存,而不是因为您使用的是First()Find()

答案 2 :(得分:0)

使用AsNoTracking()

//the value of Balance is Zero
        var account =
            context.Accounts.AsNoTracking().First(acc => acc.Id == new Guid("79B7AAC6-AD2D-4824-907E-16ADB4C41EE1"));