Sdílet prostřednictvím


Using DbContext in EF 4.1 Part 11: Load and AsNoTracking

 


The information in this post is out of date.

Visit msdn.com/data/ef for the latest information on current and past releases of EF.

For Load see https://msdn.com/data/jj592911

For AsNoTracking see https://msdn.com/data/jj556203


 

Introduction

Version 4.1 of the Entity Framework contains both the Code First approach and the new DbContext API. This API provides a more productive surface for working with the Entity Framework and can be used with the Code First, Database First, and Model First approaches. This is the eleventh post of a twelve part series containing collections of patterns and code fragments showing how features of the new API can be used.

The posts in this series do not contain complete walkthroughs. If you haven’t used EF 4.1 before then you should read Part 1 of this series and also Code First Walkthrough or Model and Database First with DbContext before tackling this post.

Load

In several of the parts in this series we have wanted to load entities from the database into the context without immediately doing anything with those entities. A good example of this is loading entities for data binding as described in Part 7. One common way to do this is to write a LINQ query and then call ToList on it, only to immediately discard the created list. The Load extension method works just like ToList except that it avoids the creation of the list altogether.

Here are two examples of using Load. The first is taken from a Windows Forms data binding application where Load is used to query for entities before binding to the local collection, as described in Part 7:

 protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    
    _context = new ProductContext();

    _context.Categories.Load();
    categoryBindingSource.DataSource =
        _context.Categories.Local.ToBindingList();
}

The second example shows using Load to load a filtered collection of related entities, as described in Part 6:

 using (var context = new UnicornsContext())
{
    var princess = context.Princesses.Find(1);

    // Load the unicorns starting with B related to a given princess
    context.Entry(princess)
        .Collection(p => p.Unicorns)
        .Query()
        .Where(u => u.Name.StartsWith("B"))
        .Load();
}

No-tracking queries

Sometimes you may want to get entities back from a query but not have those entities be tracked by the context. This may result in better performance when querying for large numbers of entities in read-only scenarios. A new extension method AsNoTracking allows any query to be run in this way. For example:

 using (var context = new UnicornsContext())
{
    // Query for all unicorns without tracking them
    var unicorns1 = context.Unicorns.AsNoTracking();

    // Query for some unitcorns without tracking them
    var unicorns2 = context.Unicorns
                        .Where(u => u.Name.EndsWith("ky"))
                        .AsNoTracking()
                        .ToList();
} 

In a sense Load and AsNoTracking are opposites. Load executes a query and tracks the results in the context without returning them. AsNoTracking executes a query and returns the results without tracking them in the context.

Summary

In this part of the series we looked the Load extension method for loading entities into the context and the AsNoTracking extension method for returning entities without tracking them.

As always we would love to hear any feedback you have by commenting on this blog post.

For support please use the Entity Framework Forum.

Arthur Vickers

Developer

ADO.NET Entity Framework

Comments

  • Anonymous
    February 05, 2011
    Thanks for this and the other  articles, they are a great resource.  I have a query about the tracking of NEW objects. I am re-coding parts of an existing application to use EF Codefirst CTP5 as an exercise. I think the issue I am seeing is not related to Codefirst, but just EF in general. Part of the application has to daily read in a textfile of  about 1,000,000 records (the identity is an 'int' so nice and simple). May of these entries will be the same, with maybe 1-2% changing from day to day. Currently a 'simple' call to a stored procedure does this task. Us EF I have a problem, to describe it, I'll take the easiest scenerio, the destination table is empty. I open a stream and start add the records with something like                             myContext.myEntity.Add(myNewrecord); To start the program flies, but as the number of records grow, it gets slower and slower. Adding in calls to myContext.SaveChanges() does not make any difference. The context is storing a copy of my record for change tracking. And even after a thousand records have been added it starts to slow. By the time its  got to 100,000 records I stop the test load! I can simply create a new context for every insert. But that Can you stop change tracking on an insert, or is there a way of clearing the cached copies from the context, other than disposing the context and starting a new one. Its an extreme example in terms of records, but the reason I decided to post this was the performance hit after only a few thousand inserts. Of course I can still call the stored proc and use EF, but I am quite excited about the posibilities of EF/Codefirst and want to establish its limits. Below is a mock up of the real code, gives an idea of what I've done. using (var  myContext = new DbContext()) { using (StreamReader sr = new StreamReader("millionrecords.txt"))               { while (true)  {                    string readLine = sr.ReadLine();                    if (readLine == null)                        break;                   var myNewrecord = CreatemyEntityFromText(readline);                    myContext.myEntity.Add(myNewrecord);  } } }             I'd be greatful for any suggestions, or should I wait until Part 12!

  • Anonymous
    February 05, 2011
    Okay, The answer is here! www.asp.net/.../maximizing-performance-with-the-entity-framework-in-an-asp-net-web-application Thanks guys!

  • Anonymous
    February 07, 2011
    @DotNetGuy You should check out Part 12 of this series since I suspect that just disabling automatic detect changes while you do the Adds is what you need.

  • Anonymous
    February 07, 2011
    Will these  functions (and the other ones that have been shown in the other parts) also make its way to the IDbSet interface? So that we may use these functions with 'fake' context objects?

  • Anonymous
    February 09, 2011
    Nevermind, i should have added a "using System.Data.Entity;". Then load is available on the IDbSet collections..

  • Anonymous
    November 19, 2011
    Is setting DbContext.Configuration.AutoDetectChangesEnabled = false the equivalent of using the AsNoTracking() extension method on a global basis? If not, how would you be able to do this? I don't want to have to add AsNoTracking() to all my LINQ queries. We used to be able at least do this at the ObjectSet level using MergeOption in EF4.0. In LINQToSQL we can do this at the context level with ObjectTrackingEnabled. AsNoTracking() allows for more granularity, but it's a step backward in terms of code reusability if you can't also control this on a more global basis as well.

  • Anonymous
    January 24, 2012
    @zl1: AsNoTracking and AutoDetectChangesEnabled are two different things. AsNoTracking is used to query for objects without having them tracked by the context at all. Setting AutoDetectChangesEnabled to false stops automatic detection of changes for objects that are being tracked. There isn’t currently a way to set AsNoTracking for all queries of a context. However, you can easily expose methods on your context that return no-tracking queries for your sets and always use these as the roots for your queries. Thanks, Arthur