Reputation: 26897
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
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