实体框架和存储库模式(IQueryable的问题)

Joh*_*ika 7 .net c# entity-framework iqueryable entity-framework-4

我刚刚从Linq 2 SQL切换到Entity Framework,我在EF中看到了一些奇怪的行为,我希望有人可以提供帮助.我尝试使用谷歌搜索,但我无法找到同样问题的其他人.我嘲笑了一个场景来解释这种情况.

如果我直接使用EF上下文,我可以在select中进行选择.例如,这执行得非常好:

        // this is an Entity Framework context that inherits from ObjectContext
        var dc = new MyContext();

        var companies1 = (from c in dc.Companies
                          select new {
                              Company = c,
                              UserCount = (from u in dc.CompanyUsers
                                           where u.CompanyId == c.Id
                                           select u).Count()
                          }).ToList();
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用存储库返回IQueryable(甚至是ObjectSet或ObjectQuery)的存储库模式,我会得到一个NotSupportedException(LINQ to Entities无法识别方法'System.Linq.IQueryable`1)...

这是我的存储库的一个例子:

public class Repository {
    private MyContext _dc;

    public Repository() {
        _dc = new MyContext();
    }

    public IQueryable<Company> GetCompanies() {
        return _dc.Companies;
    }

    public IQueryable<CompanyUser> GetCompanyUsers() {
        return _dc.CompanyUsers;
    }
}
Run Code Online (Sandbox Code Playgroud)

//我在另一个类中使用存储库(例如在我的Services层中)

        var repository = new Repository();

        var companies2 = (from c in repository.GetCompanies()
                          select new {
                              Company = c,
                              UserCount = (from u in repository.GetCompanyUsers()
                                           where u.CompanyId == c.Id
                                           select u).Count()
                          }).ToList();
Run Code Online (Sandbox Code Playgroud)

上面的代码抛出NotSupportedException.

我意识到,如果公司和公司用户之间存在关联,那么我可以简单地做到这一点并且它可以正常工作:

        var companies3 = (from c in repository.GetCompanies()
                          select new {
                              Company = c,
                              UserCount = (from u in c.CompanyUsers
                                           select u).Count()
                          }).ToList();
Run Code Online (Sandbox Code Playgroud)

...但我的例子只是一个更复杂的场景的简化版本,我没有实体之间的关联.

所以我很困惑为什么Entity Framework会抛出NotSupportedException.当我直接使用EF上下文时,查询是如何工作完全正常的,但如果我正在使用从另一个方法返回的IQueryable,则不支持它.这与Linq 2 SQL完美配合,但它似乎在Entity Framework中不起作用.

任何见解将不胜感激.

提前致谢.

Gab*_*abe 7

我怀疑发生的事情是EF看到repository.GetCompanyUsers()lambda内部的表达式为第一个select,并且不知道如何处理它,因为repository它不是EF上下文.我认为如果直接传递IQueryable而不是返回它的表达式,它应该可以工作.

如果你这样做怎么样:

    var companyUsers = repository.GetCompanyUsers();
    var companies2 = (from c in repository.GetCompanies() 
                      select new { 
                          Company = c, 
                          UserCount = (from u in companyUsers 
                                       where u.CompanyId == c.Id 
                                       select u).Count() 
                      }).ToList(); 
Run Code Online (Sandbox Code Playgroud)

  • Rei,只有一次往返数据库,因为第一个表达式不会触发数据库查询,直到它在第二个表达式中执行.我用SQL Profiler证实了这一点. (2认同)