2013-05-29 4 views
76

У меня есть список, содержащий идентификаторы моей таблицы UserProfile. Как я могу выбрать все UserProfiles на основе списка Id, которое я получил в var, используя LINQ?Выберите несколько записей на основе списка идентификаторов с linq

var idList = new int[1, 2, 3, 4, 5]; 
var userProfiles = _dataContext.UserProfile.Where(......); 

Я застрял прямо здесь. Я могу сделать это, используя для циклов и т. Д. Но я предпочел бы это сделать с LINQ.

+4

Поиск и поиск 2 разных предмета. Но так как вы можете взглянуть через мое плечо, хотя в интернете, не могли бы вы рассказать мне, как вы знаете, что я не искал?подождите, не говорите! Вы это правильно поняли? моя точка точно. – Yustme

+4

Задавая вопрос, стоит больше времени, чем на поиск. в следующий раз просто предположим, что «он/она» выполнил поиск или 10. – Yustme

+1

Это все еще привлекает к себе внимание, поэтому я подумал, что я бы сказал, что ReSharper делает очень хорошую работу, предлагая места, где вы можете превратить итеративный код в операторы LINQ , Для людей, знакомых с LINQ, это может быть незаменимым инструментом для этой цели в одиночку. – Yuck

ответ

133

Для этого вы можете использовать Contains(). Он будет чувствовать себя немного назад, когда вы на самом деле пытаетесь произвести IN положение, но это должно сделать это:

var userProfiles = _dataContext.UserProfile 
           .Where(t => idList.Contains(t.Id)); 

Я также предполагаю, что каждый UserProfile запись будет иметь intId поле. Если это не так, вам придется соответствующим образом настроить.

+0

Привет, да, записи userprofile содержат идентификаторы. Так почему-то я буду делать что-то вроде t => t.id == idList.Contains (id)? – Yustme

+0

'Contains()' будет обрабатывать эту проверку равенства для каждого значения 'id', если вы используете его, как я написал в ответе. Вам не нужно явно писать '==' где угодно, когда вы пытаетесь сравнить элементы одного набора (массив) с другим (таблица базы данных). – Yuck

+0

Ну, проблема в том, что t хранит весь объект UserProfile, а idList содержит только int. Компилятор жаловался на что-то, но мне удалось это исправить. Благодарю. – Yustme

12

Это должно быть просто. Попробуйте следующее:

var idList = new int[1, 2, 3, 4, 5]; 
var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e)); 
52

Решение с .Where и .Contains имеет сложность O (N квадрата). Простой .Join должен иметь намного лучшую производительность (близко к O (N) из-за хэширования). Таким образом, правильный код:

_dataContext.UserProfile.Join(idList, up => up.ID, id => id, (up, id) => up); 

И теперь результат моих измерений. Я создал 100 000 UserProfiles и 100 000 идентификаторов. Присоединение заняло 32 мс и. Где с .Contains заняло 2 минуты и 19 секунд! Я использовал чистый IEnumerable для этого тестирования, чтобы доказать мое утверждение. Если вы используете List вместо IEnumerable, .Where и .Contains будут быстрее. В любом случае разница значительна. Самый быстрый. Где. Состоит с Set <>. Все это зависит от сложности базовых колесий для. Посмотрите на this post, чтобы узнать о Linq complexity.Look на моем тестовом образце ниже:

private static void Main(string[] args) 
    { 
     var userProfiles = GenerateUserProfiles(); 
     var idList = GenerateIds(); 
     var stopWatch = new Stopwatch(); 
     stopWatch.Start(); 
     userProfiles.Join(idList, up => up.ID, id => id, (up, id) => up).ToArray(); 
     Console.WriteLine("Elapsed .Join time: {0}", stopWatch.Elapsed); 
     stopWatch.Restart(); 
     userProfiles.Where(up => idList.Contains(up.ID)).ToArray(); 
     Console.WriteLine("Elapsed .Where .Contains time: {0}", stopWatch.Elapsed); 
     Console.ReadLine(); 
    } 

    private static IEnumerable<int> GenerateIds() 
    { 
     // var result = new List<int>(); 
     for (int i = 100000; i > 0; i--) 
     { 
      yield return i; 
     } 
    } 

    private static IEnumerable<UserProfile> GenerateUserProfiles() 
    { 
     for (int i = 0; i < 100000; i++) 
     { 
      yield return new UserProfile {ID = i}; 
     } 
    } 

Консоль вывода:

Прошедшее .join Время: 00: 00: 00,0322546

Прошедшее .где. Содержит время: 00: 02: 19,4072107

+4

Можете ли вы вернуть это число цифрами? – Yustme

+2

Я отредактировал свой ответ с помощью моих измерений. –

+0

Ницца, однако, заставляет меня любопытно, какими будут тайминги, когда используется «Список». +1 – Yustme

8

Хорошие ответы abowe, но не забывайте один ВАЖНОЕ тыс - они дают разные результаты!

var idList = new int[1, 2, 2, 2, 2]; // same user is selected 4 times 
    var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e)).ToList(); 

Это вернет 2 строки из БД (и это может быть правильным, если вы хотите просто отличный выясняли список пользователей)

НО во многих случаях, вы можете хотите не выяснял list od. Вы всегда должны думать об этом, как о запросе SQL. Пожалуйста, смотрите пример с интернет магазин корзина для иллюстрации того, что происходит:

var priceListIDs = new int[1, 2, 2, 2, 2]; // user has bought 4 times item ID 2 
    var shoppingCart = _dataContext.ShoppingCart 
        .Join(priceListIDs, sc => sc.PriceListID, pli => pli, (sc, pli) => sc) 
        .ToList(); 

Это вернет результаты из БД. В этом случае использование «contains» было бы неправильным.

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