Matt Roberts
Matt Roberts

Reputation: 26897

EF 4.3 using local cache instead of re-fetching from database

Can someone explain to me why my EF (4.3) code first code below is resulting in the "old" password being retrieved.

using (var context = new CableSenseInstanceConfiguratorContext())
{
    var user = context.Installers.Where(u => u.UserName == "admin").FirstOrDefault();
    Console.WriteLine(user.Password); // Outputs "oldpassword"

    // Change the details on a different context;
    using (var context2 = new CableSenseInstanceConfiguratorContext())
    {
        var installer = context2.Installers.Single(i => i.UserName == "admin");
        installer.Password = "changed"; 
        context2.SaveChanges();
    }

    var user2 = context.Installers.Where(u => u.UserName == "admin").FirstOrDefault();
    Console.WriteLine(user2.Password); // Outputs "oldpassword"
}

The password is "oldpassword" to start. So I'm changing the password inside another context (context2), and then fetching it again into user2. I can verify that the output is "oldpassword" for both. From profiling the SQL, I can see that the password does get changed, I can also see that the code that populates user2 IS going to the database, but it's just not using those values.

I understand that EF has the concept of the Local context as a way of caching and tracking entities, but from what I understand, a context.Installers.Where(..) should force a refetch from the database, whereas a context.Installers.Find() should look in the local context. It seems that no matter how I query Installers, it is using the local cache.

EDIT

Thanks to @Reinard for the solution. I was misunderstanding the docs - I read from here:

Note that DbSet and IDbSet always create queries against the database and will always involve a round trip to the database even if the entities returned already exist in the context.

So I assumed that because it would go to the database, it would re-fetch my object. What actually happened is that it went to the database, fetched the object, found I already was tracking that object (because of the previous load), and so I ended up with the old object - this is actually what the docs say!

Using context.Installers.Local.Clear() makes no difference surprisingly, I needed AsNoTracking().

Upvotes: 1

Views: 1883

Answers (1)

Rei Mavronicolas
Rei Mavronicolas

Reputation: 1435

Neither Where or Find will explicitly refetch from the database. As far as I know Find will retrieve the entity from the database only if it doesn't exist in the context.

In order to explicitly force a refetch use AsNoTracking().

e.g.

context.Installers.AsNoTracking().Where(u => u.UserName == "admin").FirstOrDefault();

Upvotes: 5

Related Questions