Sélectionnez plusieurs enregistrements en fonction de la liste des identifiants avec linq

J’ai une liste contenant les identifiants de ma table UserProfile . Comment puis-je sélectionner tous les UserProfiles basés sur la liste des identifiants que j’ai obtenus dans une var utilisant LINQ ?

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

Je suis resté coincé ici. Je peux le faire en utilisant des boucles, etc. Mais je préfère le faire avec LINQ .

Vous pouvez utiliser Contains() pour cela. Vous vous sentirez un peu en arrière lorsque vous essayez vraiment de produire une clause IN , mais cela devrait le faire:

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

Je suppose également que chaque enregistrement UserProfile aura un champ int Id . Si ce n’est pas le cas, vous devrez ajuster en conséquence.

Solution avec .Where et .Contains a la complexité de O (carré N). Simple .Join devrait avoir de meilleures performances (proche de O (N) en raison du hachage). Le code correct est donc:

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

Et maintenant le résultat de ma mesure. J’ai généré 100 000 UserProfiles et 100 000 ID. Join a pris 32ms et. Où .Contains a pris 2 minutes et 19 secondes! J’ai utilisé IEnumerable pure pour ce test pour prouver mon affirmation. Si vous utilisez List au lieu de IEnumerable, .Where et .Contains seront plus rapides. En tout cas, la différence est significative. Le plus rapide. Où .Contient est avec Set <>. Tout dépend de la complexité des colonnes sous-jacentes pour .Contains. Regardez cet article pour en savoir plus sur la complexité de linq. Regardez mon exemple de test ci-dessous:

  private static void Main(ssortingng[] 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 GenerateIds() { // var result = new List(); for (int i = 100000; i > 0; i--) { yield return i; } } private static IEnumerable GenerateUserProfiles() { for (int i = 0; i < 100000; i++) { yield return new UserProfile {ID = i}; } } 

Sortie de la console:

Écoulé. Joindre l'heure: 00: 00: 00.0322546

Elapsed .Où .Contains: 00: 02: 19.4072107

Cela devrait être simple. Essaye ça:

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

De bonnes réponses s’offrent à vous, mais n’oubliez pas une chose IMPORTANTE – elles donnent des résultats différents!

  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(); 

Cela retournera 2 lignes de la firebase database (et cela pourrait être correct si vous voulez juste une liste distincte d’utilisateurs)

MAIS dans de nombreux cas, vous pourriez vouloir une liste de résultats non sortingés . Vous devez toujours y penser comme pour une requête SQL. S’il vous plaît voir l’exemple avec le panier d’achat eshop pour illustrer ce qui se passe:

  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(); 

Cela retournera 5 résultats de DB. Utiliser ‘contains’ serait erroné dans ce cas.