分类目录归档:EntityFramework

LINQ中.AsEnumerable() 和 .ToList() 的区别:

  • .AsEnumerable()延迟执行,不会立即执行。当你调用.AsEnumerable()的时候,实际上什么都没有发生。
  • .ToList()立即执行
  • 当你需要操作结果的时候,用.ToList(),否则,如果仅仅是用来查询不需要进一步使用结果集,并可以延迟执行,就用.AsEnumerable()/IEnumerable /IQueryable
  • .AsEnumerable()虽然延迟执行,但还是访问数据库,而.ToList()直接取得结果放在内存中。比如我们需要显示两个部门的员工时,部门可以先取出放置在List中,然后再依次取出各个部门的员工,这时访问的效率要高一些,因为不需要每次都访问数据库去取出部门。
  • IQueryable实现了IEnumberable接口。但IEnumerable 换成IQueryable后速度提高很多。原因:
    IQueryable接口与IEnumberable接口的区别: IEnumerable 泛型类在调用自己的SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了,而IQueryable 是将Skip ,take 这些方法表达式翻译成T-SQL语句之后再向SQL服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤。
  • IEnumerable跑的是Linq to Object,强制从数据库中读取所有数据到内存先。

Entity Framework Loading Related Entities

Entity Framework supports three ways to load related data – eager loading, lazy loading and explicit loading. The techniques shown in this topic apply equally to models created with Code First and the EF Designer.
 

Eagerly Loading

Eager loading is the process whereby a query for one type of entity also loads related entities as part of the query. Eager loading is achieved by use of the Include method. For example, the queries below will load blogs and all the posts related to each blog.

using (var context = new BloggingContext())
{
  // Load all blogs and related posts
  var blogs1 = context.Blogs
                .Include(b => b.Posts)
                .ToList();
  // Load one blogs and its related posts
  var blog1 = context.Blogs
                .Where(b => b.Name == “ADO.NET Blog”)
                .Include(b => b.Posts)
                .FirstOrDefault();
  // Load all blogs and related posts
  // using a string to specify the relationship
  var blogs2 = context.Blogs
                .Include(“Posts”)
                .ToList();
  // Load one blog and its related posts
  // using a string to specify the relationship
  var blog2 = context.Blogs
                .Where(b => b.Name == “ADO.NET Blog”)
                .Include(“Posts”)
                .FirstOrDefault();
}
Note that Include is an extension method in the System.Data.Entity namespace so make sure you are using that namespace.

Eagerly loading multiple levels

It is also possible to eagerly load multiple levels of related entities. The queries below show examples of how to do this for both collection and reference navigation properties.

using (var context = new BloggingContext())
{
  // Load all blogs, all related posts, and all related comments
  var blogs1 = context.Blogs
                 .Include(b => b.Posts.Select(p => p.Comments))
                 .ToList();
  // Load all users their related profiles, and related avatar
  var users1 = context.Users
                .Include(u => u.Profile.Avatar)
                .ToList();
  // Load all blogs, all related posts, and all related comments
  // using a string to specify the relationships
  var blogs2 = context.Blogs
                 .Include(“Posts.Comments”)
                 .ToList();
  // Load all users their related profiles, and related avatar
  // using a string to specify the relationships
  var users2 = context.Users
                .Include(“Profile.Avatar”)
                .ToList();
}
Note that it is not currently possible to filter which related entities are loaded. Include will always being in all related entities.
 

Lazy Loading

Lazy loading is the process whereby an entity or collection of entities is automatically loaded from the database the first time that a property referring to the entity/entities is accessed. When using POCO entity types, lazy loading is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook. For example, when using the Blog entity class defined below, the related Posts will be loaded the first time the Posts navigation property is accessed:

public class Blog
{
  public int BlogId { get; set; }
  public string Name { get; set; }
  public string Url { get; set; }
  public string Tags { get; set; }
  public virtual ICollection Posts { get; set; }
}

Turning off lazy loading for specific navigation properties

Lazy loading of the Posts collection can be turned off by making the Posts property non-virtual:

public class Blog
{
  public int BlogId { get; set; }
  public string Name { get; set; }
  public string Url { get; set; }
  public string Tags { get; set; }
  public ICollection Posts { get; set; }
}
Loading of the Posts collection can still be achieved using eager loading (see?Eagerly loading related entities?above) or the Load method (see?Explicitly loading related entities?below).

Turn off lazy loading for all entities

Lazy loading can be turned off for all entities in the context by setting a flag on the Configuration property. For example:

public class BloggingContext : DbContext
{
    public BloggingContext()
    {
        this.Configuration.LazyLoadingEnabled = false;
    }
}
Loading of related entities can still be achieved using eager loading (see?Eagerly loading related entities?above) or the Load method (see?Explicitly loading related entities?below).
 

Explicitly Loading

Even with lazy loading disabled it is still possible to lazily load related entities, but it must be done with an explicit call. To do so you use the Load method on the related entity’s entry. For example:

using (var context = new BloggingContext())
{
  var post = context.Posts.Find(2);
  // Load the blog related to a given post
  context.Entry(post).Reference(p => p.Blog).Load();
  // Load the blog related to a given post using a string
  context.Entry(post).Reference(“Blog”).Load();
  var blog = context.Blogs.Find(1);
  // Load the posts related to a given blog
  context.Entry(blog).Collection(p => p.Posts).Load();
  // Load the posts related to a given blog
  // using a string to specify the relationship
  context.Entry(blog).Collection(“Posts”).Load();
}
Note that the Reference method should be used when an entity has a navigation property to another single entity. On the other hand, the Collection method should be used when an entity has a navigation property to a collection of other entities.

Applying filters when explicitly loading related entities

The Query method provides access to the underlying query that the Entity Framework will use when loading related entities. You can then use LINQ to apply filters to the query before executing it with a call to a LINQ extension method such as ToList, Load, etc. The Query method can be used with both reference and collection navigation properties but is most useful for collections where it can be used to load only part of the collection. For example:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(1);
    // Load the posts with the ‘entity-framework’ tag related to a given blog
    context.Entry(blog)
        .Collection(b => b.Posts)
        .Query()
        .Where(p => p.Tags.Contains(“entity-framework”)
        .Load();
    // Load the posts with the ‘entity-framework’ tag related to a given blog
    // using a string to specify the relationship
    context.Entry(blog)
        .Collection(“Posts”)
        .Query()
        .Where(p => p.Tags.Contains(“entity-framework”)
        .Load();
}
When using the Query method it is usually best to turn off lazy loading for the navigation property. This is because otherwise the entire collection may get loaded automatically by the lazy loading mechanism either before or after the filtered query has been executed.
Note that while the relationship can be specified as a string instead of a lambda expression, the returned IQueryable is not generic when a string is used and so the Cast method is usually needed before anything useful can be done with it.
 

Using Query to count related entities without loading them

Sometimes it is useful to know how many entities are related to another entity in the database without actually incurring the cost of loading all those entities. The Query method with the LINQ Count method can be used to do this. For example:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(1);
    // Count how many posts the blog has
    var postCount = context.Entry(blog)
                          .Collection(b => b.Posts)
                          .Query()
                          .Count();
}