显然,根据this,如果不加载整个集合,就无法查询多个关系。换句话说,它是LINQ to Objects
而不是LINQ to Entities
查询。
E.g。
Category category = db.Categories.Find(1);
var productsThatStartWithA = category.Products.Where(p => p.Name.StartsWith("A")).ToList();
以上查询加载该类别中的所有产品,然后应用过滤器。
问题#1
这是对的吗?我无法相信这是多么愚蠢。
问题#2
LINQ to SQL
或任何其他LINQ
启用ORM
是否按照预期的方式处理?
linked question和Slauma's答案中提供的替代方案是解决方法,而非解决方案。它们需要对上下文对象的引用,如果您编写的代码与Entity Framework API分离,并且/或者您的代码是面向对象的,则不可用,例如:
public class Category {
public IEnumerable<Product> GetProductsThatStartWithA() {
return this.Products.Where(p => p.Name.StartsWith("A")).ToList()
}
}
答案 0 :(得分:2)
令人遗憾的是,Linq to SQL实际上为此提供了更好的支持(使用DataLoadOptions.AssociateWith
但它仍然不是您想要的)而Linq to entities / EF仅提供您所谓的解决方法 - 即使尊重对于IEnumerable
和IQueryable
之间的实施和现有差异,它看起来像是正确的解决方案。
如果未加载集合= linq-to-entities或加载集合上的常见linq-to-objects,则需要集合来公开IQueryable
并在内部调用@Slauma显示的代码。我不确定它是否可以工作,但你可以玩它。这里有一些起点:
顺便说一下。你必须关闭EF的延迟加载,否则它将优先。
答案 1 :(得分:1)
像示例中的查询之类的查询只能在内存中进行(LINQ to Objects)是不正确的。
您可以通过两次往返向数据库实现集合的过滤加载 - 请参阅Ladislav对链接问题的答案中的选项1。要将其转换为具体示例,它将如下所示:
Category category = db.Categories.Find(1);
var productsThatStartWithA = db.Entry(category)
.Collection(c => c.Products)
.Query()
.Where(p => p.Name.StartsWith("A"))
.ToList();
这不会加载完整的Products
集合,只会加载过滤集。它是LINQ to Entities而不是LINQ to Objects,它可以使用和不使用延迟加载。
此外,通过投射到匿名类型,您可以通过单个往返和单个查询获得相同的结果:
var result = db.Categories.Where(c => c.Id == 1)
.Select(c => new
{
Category = c,
ProductsStartingWithA = c.Products.Where(p => p.Name.StartsWith("A"))
})
.SingleOrDefault();
您可以在result.Category
和result.ProductsStartingWithA
中获得类别和过滤产品系列。
答案 2 :(得分:0)
您需要记住LINQ to Entities和LINQ to Objects之间的区别。
LINQ to Entities中的.Where()
将转换为SQL。 LINQ to Objects中的.Where
不会。
您可以非常轻松使用SQL来限制实体列表,方法是使用LINQ to Entities。你也可以使用LINQ to Objects轻松地避免无声地和无形地生成数据库查询。
简而言之,差异的存在恰恰是因为,正如您所暗示的那样,有时使用SQL是好的(但不是每次都使用!)。如果这对你来说似乎是“愚蠢的”,那么我会温和地建议你花一些时间来克服你期望事情如何运作并了解他们实际上是如何工作的。如果您的期望与实施一致,那么确实有意义。