2010-12-14 46 views
1

我很难将一个复杂的sql查询重写为linq。非常复杂的linq

-- gets the SpecificationAttributeOptionIDs that are in the FilteredSpecs list, but don't match 
    SELECT * FROM #FilteredSpecs [fs] 
          WHERE [fs].SpecificationAttributeOptionID NOT IN 
          ( 
           -- gets the SpecificationAttributeOptionIDs that match 
           SELECT psam.SpecificationAttributeOptionID 
           FROM dbo.Nop_Product_SpecificationAttribute_Mapping psam 
           WHERE psam.AllowFiltering = 1 AND psam.ProductID = 1 
          ) 

基本上我有什么,是一个名单FilteredSpec这是C#是一个int列表。我试图从FilteredSpec列表中获取所有包含所有属性选项的产品。

我已经试过这是(这给我有限的LINQ的知识显然是行不通的):

var query = from p in Products 
         where (p.NpProductSpecificationAttributes.Select(a => filters.Contains(a.NpSpecificationAttributeOption.SpecificationAttributeOptionId)).Count() == 0) 
         select p; 

任何人都可以指导我在正确的方向吗?

回答

2

这可能是最简单的:

var query = Products.Where(
    p => FilteredSpec.All(
     fs => p.NpProductSpecificationAttributes.Any(
      a => a.NpSpecificationAttributeOption.AllowFiltering && 
       a.NpSpecificationAttributeOption.SpecificationAttributeOptionId == fs))); 

这是可能的LINQ到实体将不知道如何翻译这个如果FilteredSpec实际上是一个List对象。如果是这样的话,让我知道,我们会看看我们是否可以想出其他解决方案。

+0

哇。谢谢。你是一个linq天才:))他们都工作,并认为第二个是更快一点,清洁的SQL。我还没有想出如何测试NpProductSpecificationAttribute是否将AllowFiltering属性设置为true – 2010-12-14 19:04:41

+0

我最终设法对该属性进行了测试。虽然我更容易。感谢您的解决方案。你是最棒的! – 2010-12-14 19:14:46

+1

@Tudor Carean:我编辑了第二个答案来检查AllowFiltering属性,并摆脱了第一个答案(这会更复杂)。 – StriplingWarrior 2010-12-14 19:20:10

4

首先,不要使用Count(),除非您真的需要确切知道有多少元素。使用Count()来测试空集可能需要遍历整个数据集。当您的数据集大小超过少数项目时,这对性能至关重要。使用 ! .Any()代替.Count()== 0,.Any()代替.Count()> 0.

接下来,您在原始SQL中的NOT IN测试听起来像是一组差异操作。在LINQ中,用.Except表示.Except()A.Except(B)返回A中未找到的所有元素B.

我对你的问题描述有点困惑。在文本中,您说您想要查找包含FilterSpec列表中找到的所有属性选项的所有产品。但是在你的两个代码示例中,你都使用NOT IN或测试Contains返回一个空的结果,这似乎是在与文本描述相反的方向上运行。

如果您试图查找所有具有FilterSpec列表中找到的所有属性选项的产品,那么您正在查找集合等价。

如果您的属性选项和您的filterspec列表中的项目总是以特定顺序列出,那么您可以使用Linq的.SequenceEqual()函数。我假设你的属性选项没有排序,所以.SequenceEqual()不是正确的解决方案。

要测试两组值A和B的等价性与顺序无关,您可以测试A.Except(B)为空且B.Except(A)为空。使用 ! .Any()测试为空。第一个说A中的所有东西都可以在B中找到,第二个说B中的所有东西都可以在A中找到。还有什么?没什么,所以这两套必须包含完全相同的元素。

尝试这样的事情(未测试):

var query = from p in Products 
      where !p.NpProductSpecificationAttributes.Except(filters).Any() && 
        !filters.Except(p.NpProductSpecificationAttributes).Any() 
      select p; 

您可以通过使用一个HashSet可能会获得更好的性能,如果仅仅是为了减少时间hashsets的数量必须在内部通过上面的表达式来创建。下面的代码假定过滤器列表和产品属性中没有重复的项目。如果您的SpecificationAttributeOptionId不是原始类型(string,int),那么您可能还需要指定一个相等比较器。

var filterset = new HashSet<filteritemtype>(filters); 
    var query = from p in Products 
       where filterset.SetEquals(new HashSet<itemtype>(p.NpProductSpecificationAttributes)) 
       select p;