it-swarm.com.de

Wählen Sie mehrere Datensätze basierend auf der Liste der IDs mit linq aus

Ich habe eine Liste mit IDs meiner Tabelle UserProfile. Wie kann ich alle UserProfiles auswählen, basierend auf der Liste der IDs, die ich in einem var mit LINQ erhalten habe?

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

Ich bin hier festgefahren. Ich kann das mit for-Schleifen usw. machen. Aber ich mache das lieber mit LINQ.

104
Yustme

Sie können dafür Contains() verwenden. Es wird sich ein wenig rückwärts anfühlen, wenn Sie wirklich versuchen, eine IN -Klausel zu erzeugen, aber dies sollte es tun:

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

Ich gehe auch davon aus, dass jeder UserProfile Datensatz ein intId Feld haben wird. Wenn dies nicht der Fall ist, müssen Sie entsprechend anpassen.

180
Yuck

Die Lösung mit .Where und .Contains hat die Komplexität von O (N Quadrat). Einfaches .Join sollte eine viel bessere Leistung haben (in der Nähe von O(N) aufgrund von Hashing). Der richtige Code lautet also:

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

Und jetzt Ergebnis meiner Messung. Ich habe 100 000 UserProfiles und 100 000 IDs generiert. Join dauerte 32ms und .Where with .Contains dauerte 2 Minuten und 19 Sekunden! Ich habe reines IEnumerable für diesen Test verwendet, um meine Aussage zu beweisen. Wenn Sie List anstelle von IEnumerable verwenden, sind .Where und .Contains schneller. Auf jeden Fall ist der Unterschied erheblich. Der schnellste .Where .Contains ist mit Set <>. Alles hängt von der Komplexität der zugrunde liegenden Spalten für .Contains ab. Schauen Sie sich diesen Beitrag an, um mehr über die Komplexität von Linq zu erfahren. Schauen Sie sich mein Testbeispiel unten an:

    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};
        }
    }

Konsolenausgabe:

Abgelaufen. Beitrittszeit: 00: 00: 00.0322546

Verstrichen .Wo. Enthält Zeit: 00: 02: 19.4072107

76
David Gregor

Schöne Antworten oben, aber vergessen Sie nicht eine WICHTIGE Sache - sie liefern unterschiedliche Ergebnisse!

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

Dies gibt 2 Zeilen aus der Datenbank zurück (und dies könnte korrekt sein, wenn Sie nur eine klar sortierte Liste von Benutzern wünschen).

ABER in vielen Fällen möchten Sie vielleicht ein unsortiertes Ergebnisliste. Sie müssen immer wie bei einer SQL-Abfrage darüber nachdenken. Bitte sehen Sie sich das Beispiel mit dem Warenkorb von eshop an, um zu veranschaulichen, was los ist:

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

Dies gibt 5 Ergebnisse von DB zurück. Die Verwendung von "enthält" wäre in diesem Fall falsch.

17
Tomino

Das sollte einfach sein. Versuche dies:

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