Laden...

Linq Materialisierung-Problem

Erstellt von Christoph K. vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.285 Views
Christoph K. Themenstarter:in
821 Beiträge seit 2009
vor 5 Jahren
Linq Materialisierung-Problem

verwendetes Datenbanksystem: MsSql + EF

Hallo zusammen,

ich nutze das EF und mache damit Querys auf die Datenbank.
Sehr häufig habe ich den Fall, das ich den Query materialisieren muss, damit ich eigene Funktionen mit einweben kann.

Folgende Funktion schlägt z.B. fehl, da "locations" kein Objekt des EF-Context ist:


var data = from ko in KeywordObservers
			join ks in KeywordSpecifications on ko.KeywordSpecificationId equals ks.Id
			join k in Keywords on ks.KeywordId equals k.Id
		   where ko.ProjectId == 5
		   select new {
		   		keyword = k.KeywordValue,
				locationId = ks.LocationId,
				valid = locations.Any(x => x.Id == ks.LocationId)
		   };

Das ist auch insoweit gar nicht schlimm, da das ganze nach einer Materialisierung des Queries funktioniert. Leider wird hierdurch sehr viel nerviger Code erzeugt, da ich alle Properties, die ich im "select new" eingebunden habe, bei meiner zweiten LINQ-Abfrage (auf das materialisierte Ergebnis der ersten Abfrage) wieder zuweisen muss.

Gibts da irgendwie etwas einfacheres?

Gruß
Christoph

16.827 Beiträge seit 2008
vor 5 Jahren

In dieser Form nicht. Der Compiler kann nicht hellsehen; die Properties sind ja namentlich auch nicht identisch.

2.079 Beiträge seit 2012
vor 5 Jahren

Kurz: Nein

EFCore ist da allerdings etwas flexibler, das führt soviel von der Query aus, wie es kann, der Rest läuft im RAM. Ob das stimmt, weiß ich nicht, ich hab's nur in der MSDN-Doku gelesen.
Wirklich gut finde ich das nicht, da dadurch (mMn.) Fehler in der Query nicht auffallen. Man kann das allerdings auch ausstellen oder in so einem Fall Warnungen ausgeben lassen.

Ich würde an deiner Stelle aber auch nicht die LINQ-Syntax verwenden, sondern die Methoden-Syntax, die macht sowas etwas einfacher:

var data = KeywordObservers
    .Where(x => /* ... */)
    .Select(x => new { A = x.AValue, B = x.BValue })
    .AsEnumerable() // Ab hier ist es keine Query sondern läuft im RAM. Daher kannst Du auch eigene Methoden nutzen
    .Select(x => new { x.A, x.B, C = GetCValue(x.C) });
16.827 Beiträge seit 2008
vor 5 Jahren

Man kann auch eigene Methoden für Linq implementieren.

Ob man ToList oder AsEnumerable feuert; prinzipiell egal - sieht man beides oft.
Beides bewirkt, dass der Query ausgeführt wird und alle weitere Abfragen nicht gegen die DB sondern gegen die Daten im RAM laufen.

Siehe auch Grundlagen Linq: Materialisierung