Выберите несколько записей на основе списка идентификаторов с linq
у меня есть список, содержащий идентификаторы мой UserProfile
таблица. Как я могу выбрать все UserProfiles
на основе списка идентификаторов, которые я получил в var
используя LINQ
?
var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(......);
Я застрял прямо здесь. Я могу сделать это, используя для петель и т. д. Но я бы предпочел сделать это с LINQ
.
4 ответа:
можно использовать
Contains()
для этого. Он будет чувствовать себя немного назад, когда вы действительно пытаетесь произвестиIN
п., Но это должно сделать это:var userProfiles = _dataContext.UserProfile .Where(t => idList.Contains(t.Id));
Я также предполагаю, что каждый
UserProfile
запись будетint
решение .Где и как .Содержит имеет сложность O (N квадрат). Простой.Соединение должно иметь намного лучшую производительность(близко к O (N) из-за хэширования). Поэтому правильный код:
_dataContext.UserProfile.Join(idList, up => up.ID, id => id, (up, id) => up);
а теперь результат моего измерения. Я сгенерировал 100 000 пользовательских профайлов и 100 000 идентификаторов. Регистрация заняла 32 МС и .Куда с ...Содержит заняло 2 минуты и 19 секунд! Я использовал чистый IEnumerable для этого тестирования, чтобы доказать свое утверждение. Если вы используете List вместо IEnumerable,.Где и как .Содержит будет быстрее. В любом случае разница существенная. Самый быстрый .Где.Содержит набор. Все это зависит от сложности лежащих в основе колеций .Содержит. Посмотри на этот пост чтобы узнать о сложности linq.Посмотрите на мой тестовый образец ниже:
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}; } }
консоль вывода:
прошедшее .Регистрация времени: 00: 00: 00.0322546
прошедшее .Где.Содержит время: 00:02:19.4072107
Это должно быть просто. Попробуйте это:
var idList = new int[1, 2, 3, 4, 5]; var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e));
хорошие ответы 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 строки из БД (и это может быть правильно, если вы просто хотите отдельный отсортированный список пользователей)
но во многих случаях, вы могли бы хотите несортированный список результатов. Вы всегда должны думать об этом, как о 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();
вернет 5 результаты из БД. Использование 'contains' было бы неправильным в этом случае.