LINQ:选择一个类别下的产品,包括子类别

问题描述:

下面的代码搜索匹配关键字s或处于与关键字s匹配的类别下的产品。LINQ:选择一个类别下的产品,包括子类别

这是工作但繁琐,我想知道是否有一个更短的方法来做到这一点?

var products = context.Products.Where(x => 
       x.Name.Contains(s) || 
       x.Products_Categories.Any(pc => 
        pc.Category.Name.Contains(s) || 
        (pc.Category.Category1 != null && pc.Category.Category1.Name.Contains(s)) || 
        (pc.Category.Category1 != null && pc.Category.Category1.Category1 != null && pc.Category.Category1.Category1.Name.Contains(s) || 
        (pc.Category.Category1 != null && pc.Category.Category1.Category1 != null pc.Category.Category1.Category1.Category1 != null && &&pc.Category.Category1.Category1.Category1.Name.Contains(s)) 
       ); 

如果这不是明摆着:

Products_Categories是许多一对多的关系,一个Product可以在一个或多个Category

Category1Category的父类别。

请注意,它链接到数据库,所以我不能使用像IsUnderCategory()这样的函数。
我现在不需要表达式,因为这段代码只用了一次。

+1

看起来应该在数据库中创建一个View来获取有关类别(使用公共表表达式)的分层数据并使用该View进行查询,而不是'Category'表本身。 – MarcinJuraszek 2013-04-04 05:50:02

在linq中没有任何递归查询的捷径,在linq中没有什么捷径可以通过SQL查询提供程序来支持。但是,在执行之前,有一条声明先被转换为SQL :SQL没有空引用的概念。所以,如果你的语句删除所有null检查:

var products = context.Products.Where(x => 
       x.Name.Contains(s) || 
       x.Products_Categories.Any(pc => 
        pc.Category.Name.Contains(s) || 
        pc.Category.Category1.Name.Contains(s) || 
        pc.Category.Category1.Category1.Name.Contains(s) || 
        pc.Category.Category1.Category1.Category1.Name.Contains(s)) 
       ); 

与许多外部联接将转换为SQL语句。正如你所知道的,如果你在没有记录时处理外连接表的字段,SQL不会崩溃。

该查询将是......怪异的。你必须假定层次结构的最大深度。唯一可以改进的方法是在数据库中创建一个视图,该视图通过recursive SQL query返回产品的所有类别。

使用EF的另一种方法是使用while循环简单查询子类别的所有类别。

完成后,您将拥有所有ID。第一次,查询计划尚未完成,它需要一段时间,但它的速度非常快,取决于数据库的怪异程度。

然后,你可以query for all products that have any of a list of category IDs使用Contains方法被翻译成WHERE FieldName IN (1,2,3)

这种方法的优点是,它不依赖于你有子类别的多少级。它始终有效,而另一种替代方式默默无闻。