实体框架:POCO的自定义代理

时间:2014-04-25 12:51:33

标签: proxy lazy-loading entity-framework-6

我正在使用EF6,我是动态代理的忠实粉丝,可以实现延迟加载和更改跟踪。无论如何,当我首先调用枚举器或count属性时,一旦访问属性而不是加载数据,就会触发延迟加载。因此,我试图使代理变得可行,并用自定义代理替换它们。使用自定义对象上下文并重载CreateObject方法是一件容易的事情。遗憾的是,ObjectMaterialized事件无法替换实体,我无法从查询中替换实体。对象的创建深入于框架的内部类。

有人知道如何使用自定义代理吗?或者我如何能够替换对象查询中实现的实体?

1 个答案:

答案 0 :(得分:1)

您应该.Include要获取的属性,以避免N+1 query problem

public class User
{
    public int Id { get; set; }
    public string Name { get; set ;}

    public virtual ICollection<Post> Posts { get; set; }
    public virtual ICollection<Comment> Comments { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set ; }

    public int AuthorId { get; set; }
    public virtual User Author { get; set; }

    public virtual ICollection<Comment> Comments { get; set; }
}

public class Comment
{
    public int Id { get; set; }
    public string Note { get; set ;}

    public int PostId { get; set; }
    public virtual Post Post { get; set; }

    public int AuthorId { get; set; }
    public virtual User Author { get; set; }
}

public class BlogContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<Comment> Comments { get; set; }
} 

然后这是 BAD ,因为它会进行大量查询:

using (var db = new BlogContext())
{
    var user = db.Users.Single(u => u.Id=5));  // +1 query
    foreach (var post in user.Posts) // N queries
    {
       var message = String.Format("{0} wrote {1}", user.Name, post.Title);
       Console.WriteLine(message);

       foreach (var comment in post.Comments) // N * M queries!
       {
           // and that .Author make N * M MORE!
           var message = String.Format("\t{0} commented {1}", comment.Author.Name, comment.Note);
           Console.WriteLine(message);
       }
    }
}

这是 GOOD ,因为它会一个查询:

using (var db = new BlogContext())
{
    var user = db.Users
                 .Single(u => u.Id=5))
                 .Include(u => u.Posts) // eliminates the N post queries
                 .Include(u => u.Posts.Comments) // eliminates the M comment queries
                 .Include(u => u.Posts.Comments.Author); // eliminates the M comment author queries

    foreach (var post in user.Posts) // N queries
    {
       var message = String.Format("{0} wrote {1}", user.Name, post.Title);
       Console.WriteLine(message);

       foreach (var comment in post.Comments) // N * M queries!
       {
           // and that .Author make N * M MORE!
           var message = String.Format("\t{0} commented {1}", comment.Author.Name, comment.Note);
           Console.WriteLine(message);
       }
    }
}