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

时间:2013-04-04 05:34:24

标签: linq entity-framework

以下代码搜索与关键字s匹配或位于与关键字s匹配的类别下的产品。

它工作但很乏味,我想知道是否有更短的方法来做到这一点?

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()等功能 我目前不需要Expression,因为这段代码只使用一次。

2 个答案:

答案 0 :(得分:1)

在linq中没有递归查询的快捷方式,在SQL查询提供程序支持的linq中则不那么快。但是,在执行之前,语句首先被转换为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返回产品的所有类别。

答案 1 :(得分:0)

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

完成后,您拥有所有ID。第一次,查询计划还没有完成,需要一点时间,但是它的速度非常快,具体取决于您的数据库是多么可怕。

然后您可以query for all products that have any of a list of category IDs使用转化为Contains的{​​{1}}方法

这种方法的优点在于它不依赖于您拥有多少级别的子类别。它始终有效,而另一种选择无声地失败。