2014-02-20 4 views
6

Я пытаюсь использовать 'contains', чтобы имитировать старый SQL ', где id в (1,2,3,4)' способ фильтрации запроса.C# linq выражение в лямбда с содержит

Однако у меня есть некоторые трудности с его использованием, когда мои идентификаторы находятся на более глубоком уровне.

Код:

public class Category 
    { 
     public long Id { get; set; } 
     public string Name { get; set; } 
    } 

    public class Characteristica 
    { 
     public Category Category { get; set; } 
     public int Id { get; set; } 
     public string Value { get; set; } 
    } 

    public class Person 
    { 
     public string Name { get; set; } 
     public List<Characteristica> Appearance { get; set; } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var persons = new List<Person> 
      { 
       new Person { Name = "Person A", Appearance = new List<Characteristica> { new Characteristica { Id = 22 }, new Characteristica { Id = 5 }, new Characteristica { Id = 12 } }}, 
       new Person { Name = "Person B", Appearance = new List<Characteristica> { new Characteristica { Id = 1 }, new Characteristica { Id = 6 }, new Characteristica { Id = 11 } }}, 
       new Person { Name = "Person C", Appearance = new List<Characteristica> { new Characteristica { Id = 2 }, new Characteristica { Id = 8 }, new Characteristica { Id = 13 } }}, 
       new Person { Name = "Person D", Appearance = new List<Characteristica> { new Characteristica { Id = 2 }, new Characteristica { Id = 5 }, new Characteristica { Id = 10 } }}, 
       new Person { Name = "Person E", Appearance = new List<Characteristica> { new Characteristica { Id = 1 }, new Characteristica { Id = 8 }, new Characteristica { Id = 10 } }}, 
       new Person { Name = "Person F", Appearance = new List<Characteristica> { new Characteristica { Id = 1 }, new Characteristica { Id = 6 }, new Characteristica { Id = 23 } }}, 
      }; 

      var listOfSearchedIds = new List<int> { 22, 23 }; 
      var selected = persons.Select(p => p.Appearance.Where(a => listOfSearchedIds.Contains(a.Id))).ToList(); 
     } 
    } 

Теперь я пытаюсь получить 'Person A' и 'F' Человек из моей коллекции, используя содержит Feauture. Однако я не вижу, что я делаю неправильно здесь.

Может кто-то пролить свет на то, что я делаю неправильно? Я пробовал разные версии моей лямбды, и это закрытие, которое я могу получить, но я получаю все 6 предметов из своего выражения.

+0

Что происходит? вы получаете сообщение об ошибке? Вы получаете неправильную информацию? Я предположил, что вы работаете против базы данных, но ваш пример не похож на вас. Можете ли вы поместить его на [complify.net] (https://compilify.net)? –

+0

В соответствии с ответом Маркуса, возможно, используйте HashSet, а не List for Characteristica. – Paparazzi

+0

Нет, я не ошибся. Я просто ожидал получить список того человека, который мне нужен. Мой пример - с объектами, но в реальном коде я извлекаю данные из базы данных с помощью EF 5. – codingjoe

ответ

15

Ваш путь является правильным, но вы должны использовать Where вместо Select

var selected = persons.Where(p => p.Appearance 
       .Where(a => listOfSearchedIds.Contains(a.Id)) 
       .Any()).ToList(); 

И вам нужно использовать Any, чтобы проверить, содержит ли последовательность возвращения из p.Appearance.Where любой element.Or вы можете использовать Any непосредственно и сделать его краткое:

var selected = persons.Where(p => p.Appearance 
       .Any(a => listOfSearchedIds.Contains(a.Id)) 
       .ToList(); 
+0

Выглядит очень правильно. – codingjoe

+0

Я протестировал оба метода в LINQPad 5, и они оба дали один и тот же SQL в конце. DECLARE p0 Int = 2 DECLARE p1 Int = 3 SELECT [t0]. [Id], [t0]. [Name], [t0]. [Описание], [t0]. [ModifiedBy], [t0] [Изменено], [t0]. [CreatedBy], [t0]. [CreatedDate], [t0]. [RowVersion], [t0]. [TriggerTypeGuid] FROM [TriggerType] AS [t0] WHERE EXISTS (SELECT NULL AS [EMPTY] FROM [TriggerClass] AS [t1] WHERE ([t1]. [TriggerTypeId] IN (p0, p1)) AND ([t1]. [TriggerTypeId] = [t0]. [Id])) So Селман прав, указывая на то, что любой из методов работает, а второй - короче, но может быть менее явным. –

2

Попробуйте следующее:

var listOfSearchedIds = new List<int> { 22, 23 }; 
var selected = persons 
     .Where(p => listOfSearchedIds 
         .Intersect(p.Appearance 
          .Select(a => a.Id)).Any()).ToList(); 

С помощью Intersect, сравнить два списка и вернуть элементы, которые содержатся в них обоих. Intersect внутренне использует HashSet и, следовательно, очень эффективный способ найти два пересечения двух наборов. Any() возвращает true, если в результирующем списке есть хотя бы один элемент.

+1

Intersect будет работать с LINQ для объектов, но если вы хотите это сделать с базой данных (EF/L2S), вам нужно пойти с Содержит , –

Смежные вопросы