代码之家  ›  专栏  ›  技术社区  ›  Johnny Oshika

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

  •  7
  • Johnny Oshika  · 技术社区  · 15 年前

    我刚从Linq2SQL转换到实体框架,我看到了一些我希望有人能帮助的ef中的奇怪行为。我试着到处搜索,但找不到其他有同样问题的人。我已经模拟了一个场景来解释这种情况。

    如果我直接使用一个ef上下文,我就可以在select中进行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();
    

    但是,如果我使用存储库返回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;
        }
    }
    

    //我正在另一个类中使用存储库(例如,在我的服务层中)

            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();
    

    上述代码引发NotSupportedException。

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

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

    …但是我的示例只是一个更复杂场景的简化版本,在这个场景中,实体之间没有关联。

    所以我很困惑为什么实体框架会抛出NotSupportedException。当我直接使用ef上下文时,查询如何工作得非常好,但是如果我使用从另一个方法返回的iqueryable,则不支持它。这对于Linq2SQL非常好,但在实体框架中似乎不起作用。

    任何见解都会受到极大的赞赏。

    事先谢谢。

    2 回复  |  直到 15 年前
        1
  •  7
  •   Gabe Timothy Khouri    15 年前

    我怀疑发生的事情是英孚看到了 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(); 
    
        2
  •  3
  •   Community Mohan Dere    9 年前

    这是linq-to-sql/ef的一个奇怪的怪癖。显然,他们实现了一种从getter 财产 到SQL,但不是从getter转换的方法 功能 到SQL。

    if而不是函数 GetCompanyUsers() 你使用的财产 CompanyUsers ,应该可以。

    奇怪吧?

    所以不是

    public IQueryable<CompanyUser> GetCompanyUsers() {
        return _dc.CompanyUsers;
    }
    

    你可能会的

    public IQueryable<CompanyUser> CompanyUsers {
        get { return _dc.CompanyUsers; }
    }
    

    就参数化查询而言(显然您不能使用属性),请参见此处回答的问题: Custom function in Entity Framework query sometimes translates properly, sometimes doesn't

    你也可以 wheres selects 他们也会翻译的很好。例如,如果我有一个博客,其中的文章表包含一些不在线的文章:

    public IQueryable<Article> LiveArticles {
        get { return _dc.Articles.Where(a => !a.IsDraft); }
    }
    

    这还将减少所需的参数化查询的数量。