实体框架和存储库模式(IQueryable 问题)
我刚刚从 Linq 2 SQL 切换到实体框架,我在 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();
...但我的示例只是一个更复杂场景的简化版本,其中我在实体。
所以我很困惑为什么实体框架抛出 NotSupportedException。当我直接使用 EF 上下文时,查询工作得很好,但如果我使用从另一个方法返回的 IQueryable,则不支持它。这在 Linq 2 SQL 中工作得很好,但在实体框架中似乎不起作用。
任何见解将不胜感激。
提前致谢。
I just switched from Linq 2 SQL to Entity Framework, and I'm seeing some strange behaviors in EF that I'm hoping someone can help with. I tried Googling around, but I wasn't able to find other people with this same problem. I've mocked up a scenario to explain the situation.
If I work directly with an EF context, I'm able to do a select within a select. For example, this executes perfectly fine:
// 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();
However, if I use a repository pattern where the repository is returning IQueryable (or even ObjectSet or ObjectQuery), I get a NotSupportedException (LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1)...
Here is an example of my repository:
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;
}
}
// I'm using the repository inside another class (e.g. in my Services layer)
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();
The above code throws a NotSupportedException.
I realize that if there's an association between Companies and CompanyUsers, then I can simply do this and it will work fine:
var companies3 = (from c in repository.GetCompanies()
select new {
Company = c,
UserCount = (from u in c.CompanyUsers
select u).Count()
}).ToList();
...but my example is just a simplified version of a more complicated scenario where I don't have an association between the entities.
So I'm very confused why Entity Framework is throwing the NotSupportedException. How is it that the query works perfectly fine when I'm working with the EF context directly, but it's not supported if I'm working with IQueryable returned from another method. This worked perfectly fine with Linq 2 SQL, but it doesn't seem to work in Entity Framework.
Any insight would be greatly appreciated.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我怀疑发生的情况是,EF 在第一个
select
的 lambda 中看到了repository.GetCompanyUsers()
的表达式,并且不知道如何处理它,因为 < code>repository 不是 EF 上下文。我认为如果您直接传入 IQueryable 而不是返回它的表达式,它应该可以工作。如果你这样做怎么样:
I suspect that what's happening is that EF sees the expression for
repository.GetCompanyUsers()
inside the lambda for the firstselect
and doesn't know what to do with it becauserepository
isn't an EF context. I think that if you pass in the IQueryable directly instead of an expression that returns it, it should work.How about if you do this:
这是 Linq to SQL/EF 的奇怪之处之一。显然,他们实现了一种从 getter 属性转换为 SQL 的方法,但没有实现从 getter 函数转换为 SQL 的方法。
如果您使用像
CompanyUsers
这样的属性而不是函数GetCompanyUsers()
,它应该可以工作。很奇怪吧?
因此,
您可能会执行
“就参数化查询而言”(显然,您不能使用属性来执行此操作),请参阅此处回答的我的问题: 实体框架查询中的自定义函数有时可以正确翻译,有时则不能
您还可以有
wheres
并且也在属性中选择;他们会翻译得很好。例如,如果我有一个带有 Articles 表的博客,其中包含一些不在线的文章:这也会减少您需要的参数化查询的数量。
This is one of those strange quirks with Linq to SQL/EF. Apparently they implemented a way to translate from a getter property to SQL, but not a way to translate from a getter function to SQL.
If instead of a function
GetCompanyUsers()
you use a property likeCompanyUsers
, it should work.Weird eh?
So instead of
You might do
As far as parameterized queries go (which you can't do with a property, obviously), see my question answered here: Custom function in Entity Framework query sometimes translates properly, sometimes doesn't
You can also have
wheres
andselects
in the property too; they'll translate fine. For instance, if I had a blog with an Articles table that contains some articles that aren't online:That'll also reduce the number of parameterized queries that you need.