Entity Framework AsNoTracking bricht den Aufruf von Distinct ab

8

Ich versuche eine Liste von verschiedenen Farben aus einer zuvor geladenen Liste von Produkten auf einer Seite zu laden. Also, um die Produkte anzuziehen, mache ich das:

%Vor%

Dann mache ich etwas Verarbeitung auf den Produkten, die ich möchte, um eine Liste aller verschiedenen Farben zu erhalten, die von den Produkten verwendet werden, also mache ich das:

%Vor%

Und das funktioniert gut, aber wenn ich einen Aufruf von .AsNoTracking() zum ursprünglichen Produktaufruf hinzufüge, erhalte ich jetzt einen Eintrag in meiner Farbliste für jeden Eintrag in der Produktliste.

Warum gibt es einen Unterschied in diesen beiden? Gibt es eine Möglichkeit, Entity Framework davon abzuhalten, die Objekte zu verfolgen (sie werden nur zum Lesen verwendet) und das gewünschte Verhalten zu erhalten?

Hier ist meine Abfrage nach dem Hinzufügen des Aufrufs zu AsNoTracking()

%Vor%     
heavyd 13.06.2013, 21:49
quelle

1 Antwort

19

AsNoTracking "bricht" Distinct ab, weil AsNoTracking "das Identitätsmapping durchbricht. Da Entitäten, die mit AsNoTracking() geladen sind, nicht mit dem Kontextcache verknüpft werden, materialisiert EF neue Entitäten für jede von der Abfrage zurückgegebene Zeile. Wenn die Verfolgung aktiviert ist, wird geprüft, ob eine Entität mit demselben Schlüsselwert bereits im Kontext vorhanden ist Wenn ja, würde es kein neues Objekt erstellen und stattdessen nur die angefügte Objektinstanz verwenden.

Wenn Sie beispielsweise 2 Produkte haben und beide grün sind:

  • Ohne AsNoTracking() materialisiert Ihre Anfrage 3 Objekte: 2 Product Objekte und 1 ProductColor Objekt (Grün). Produkt 1 hat eine Referenz auf Grün (in ProductColor -Eigenschaft) und Produkt 2 hat eine Referenz auf dieselbe Objektinstanz Grün, d. H.

    %Vor%
  • Mit AsNoTracking() materialisiert Ihre Abfrage 4 Objekte: 2 Produktobjekte und 2 Farbobjekte (beide repräsentieren Grün und haben denselben Schlüsselwert). Produkt 1 hat einen Verweis auf Grün (in ProductColor -Eigenschaft) und Produkt 2 hat einen Verweis auf Grün, aber dies ist eine andere Objektinstanz , d. H.

    %Vor%

Wenn Sie nun Distinct() für eine Sammlung im Speicher (LINQ-to-Objects) aufrufen, vergleicht der Standardvergleich für Distinct() ohne Parameter Objektreferenzidentitäten. In Fall 1 erhält man also nur 1 grünes Objekt, aber in Fall 2 erhält man 2 grüne Objekte.

Um das gewünschte Ergebnis zu erhalten, nachdem Sie die Abfrage mit AsNoTracking() ausgeführt haben, benötigen Sie einen Vergleich nach dem Entitätsschlüssel. Sie können entweder die zweite Überladung von Distinct verwenden, die einen IEqualityComparer als Parameter benötigt. Ein Beispiel für die Implementierung ist hier und Sie würden die Schlüsseleigenschaft von ProductColor zum Vergleichen verwenden zwei Objekte.

Oder - was mir einfacher erscheint als die langwierige IEqualityComparer Implementierung - Sie schreiben Distinct() mit GroupBy um (mit der Schlüsseleigenschaft ProductColor als Gruppierungsschlüssel):

%Vor%

Das First() bedeutet im Grunde, dass Sie alle Duplikate wegwerfen und nur die erste Objektinstanz pro Schlüsselwert behalten.

    
Slauma 14.06.2013, 22:50
quelle