【问题标题】:Entity Framework and Repository Pattern (problem with IQueryable)实体框架和存储库模式(IQueryable 的问题)
【发布时间】:2011-05-16 11:38:32
【问题描述】:

我刚刚从 Linq 2 SQL 切换到 Entity Framework,我在 EF 中看到了一些奇怪的行为,希望有人能提供帮助。我试着用谷歌搜索,但我找不到其他有同样问题的人。我已经模拟了一个场景来解释这种情况。

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

        // 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。

我意识到如果 Companies 和 CompanyUsers 之间存在关联,那么我可以简单地执行此操作,它会正常工作:

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

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

所以我很困惑为什么 Entity Framework 会抛出 NotSupportedException。当我直接使用 EF 上下文时,查询如何完美地工作,但如果我使用从另一个方法返回的 IQueryable,则不支持它。这在 Linq 2 SQL 中运行得非常好,但在实体框架中似乎不起作用。

任何见解将不胜感激。

提前致谢。

【问题讨论】:

    标签: c# .net entity-framework entity-framework-4 iqueryable


    【解决方案1】:

    我怀疑发生的事情是 EF 在第一个 select 的 lambda 中看到 repository.GetCompanyUsers() 的表达式,并且不知道如何处理它,因为 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(); 
    

    【讨论】:

    • 为什么我们需要这样做,我的意思是我们在这里有关联?
    • 这需要两次往返服务器...等等,是吗?
    • 加布,你说得对。我仍然很困惑为什么 EF 无法处理表达式,但您的解决方案效果很好。
    • Rei,数据库只有一次往返,因为第一个表达式在第二个表达式中执行之前不会触发数据库查询。我用 SQL Profiler 确认了这一点。
    【解决方案2】:

    这是 Linq to SQL/EF 的奇怪怪癖之一。显然他们实现了一种从 getter property 转换为 SQL 的方法,但没有实现从 getter 函数 转换为 SQL 的方法。

    如果您使用CompanyUsers 之类的属性而不是函数GetCompanyUsers(),它应该可以工作。

    很奇怪吧?

    所以不是

    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

    您也可以在属性中添加wheresselects;他们会翻译得很好。例如,如果我有一个博客,其中的 Articles 表包含一些不在线的文章:

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

    这也将减少您需要的参数化查询的数量。

    【讨论】:

    • 很奇怪,但你是绝对正确的。返回 IQueryable 的属性适用于 EF。 Linq to SQL 也适用于方法,但我猜 EF 没有实现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多