Entity Framework DbContext Local
Posted on: 2014-06-03
Entity Framework uses the DbContext has a proxy to the connect to the database. This one keep information that came from the database but also information set from the code. It is the middle man between your entity in your code and your entity in your database. To be more accurate, it is the Local of the DbSet that contain the DbContext where the information remain for the life time of the DbContext.
The DbContext has for every sets a local storage. This is a temporary place where information reside. It is possible to access this container to get information already queried.
The Finds
method use the Local to get for the primary key the entity before querying the database. However, method like Single and Where does not. But, it is possible to explicitly do a query against the Local. If we do a test, we see that using SingleOrDefault twice call the database twice. If we query the local with SingleOrDefault, no query is done to the database.
private static void QueryLocal() { using (var context = new YourContext()) { Console.WriteLine(context.Persons.Local.Count); //0 var newPerson = new Person { Id = 500, Name = "New Person", BirthDate = new DateTime(2000, 1, 2) }; context.Persons.Add(newPerson); Console.WriteLine(context.Persons.Local.Count); //1 var person = context.Persons.SingleOrDefault(d => d.Id == 1); //Query the database Console.WriteLine(context.Persons.Local.Count); //2 var person2 = context.Persons.SingleOrDefault(d => d.Id == 1); //Query the database again Console.WriteLine(context.Persons.Local.Count); //2 var person3 = context.Persons.Local.SingleOrDefault(d => d.Id == 1); //Does not query the database Console.WriteLine(context.Persons.Local.Count); //2 } }
Querying with a where clause load information into the Local storage but does not load everything. If you want to load all entities into your local you can use explicit loading
.
private static void ExplicitLoadIntoLocal() { using (var context = new YourContext()) { Console.WriteLine(context.Persons.Local.Count); //0 context.Persons.Load(); Console.WriteLine(context.Persons.Local.Count); //1 } }
The explicit loading do a single query that load everything from the database. The SQL profiler shows the Select statement below.
SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[BirthDate] AS [BirthDate], [Extent1].[Person_Id] AS [Person_Id], [Extent1].[Residence_Id] AS [Residence_Id], [Extent1].[House_Id] AS [House_Id] FROM [dbo].[People] AS [Extent1]
In a future article, we will see that it is possible to load with explicit loading (.Load) not everything from the database. The goal here is to show that the DbSet.Local
is filled up. It is also important to notice that if you call twice Load, it will load from the database everything. If you have one conclusion to remember from this article is that you have to be aware of which operations goes all the time to the database and which ones can are optimized by using the Local cache.
private static void ExplicitLoadIntoLocal() { using (var context = new YourContext()) { Console.WriteLine(context.Persons.Local.Count); //0 context.Persons.Load(); Console.WriteLine(context.Persons.Local.Count); //1 context.Persons.Load(); //Call the database one more time } }
If you are interested to execute the code in this post, you can get the source code from GitHub. It is also possible to get everything from a Zip file.