Очень сложный Линк - PullRequest
       14

Очень сложный Линк

1 голос
/ 14 декабря 2010

У меня проблемы с переписыванием сложного SQL-запроса как 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 ]

4 голосов
/ 14 декабря 2010

Прежде всего, никогда не используйте Count (), если вам действительно не нужно точно знать, сколько элементов существует.Использование Count () для проверки пустого набора может потребовать обхода всего набора данных.Это критично для производительности, когда размер вашего набора данных превышает несколько элементов.Используйте!.Any () вместо .Count () == 0, .Any () вместо .Count ()> 0.

Далее, ваш тест NOT IN в исходном SQL звучит как операция установки разности.В LINQ это представлено .Except () A.Except (B) возвращает все элементы A, которые не найдены в B.

Меня немного смущает описание вашей проблемы.В тексте вы говорите, что хотите найти все продукты, которые имеют все атрибуты, найденные в списке FilterSpec.Но в обоих примерах кода вы используете NOT IN или тестируете на Contains, возвращая пустой результат, который, кажется, работает в направлении, противоположном текстовому описанию.

Если вы пытаетесь найти всепродукты, которые имеют все атрибуты, найденные в списке FilterSpec, тогда вы ищете эквивалентность набора.

Если элементы в ваших атрибутах и ​​в списке их фильтров всегда перечислены в определенном порядке, то вы можете использовать Linq.SequenceEqual () функция.Я предполагаю, что ваши атрибуты не упорядочены, поэтому .SequenceEqual () не является правильным решением.

Чтобы проверить два набора значений A и B на эквивалентность, не зависящую от порядка, вы можете проверить на A.Except(B) пусто и B. Кроме (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, если толькочтобы уменьшить количество раз, хэш-наборы должны быть созданы внутри с помощью выражения выше.В приведенном ниже коде предполагается, что в списке фильтров и в атрибутах продукта нет повторяющихся элементов.Если ваш 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;
2 голосов
/ 14 декабря 2010

Это, вероятно, самое простое:

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

Возможно, что LINQ to Entities не будет знать, как это перевести, если FilteredSpec на самом деле является объектом List.Если это так, дайте мне знать, и мы посмотрим, сможем ли мы найти какое-то другое решение.

...