Die Woche haben wir im Projekt mal wieder eine Sonderaufgabe für Linq To Sql gefunden, aber dazu komme ich noch.
Wir nutzen intensiv Linq To Sql allerdings machen wir kein Lazy Loading, sondern laden unsere benötigten Objekte komplett (eager loading). Das kann man am einfachsten mit der LoadWith-Option in Linq to Sql machen.
1: var query = from m in db.ChildEntities
2: select m;
3: var options = new DataLoadOptions();
4: options.LoadWith<ChildEntities>(m=>m.ParentEntity);
5: options.LoadWith<ChildEntities>(m=>m.ChildChildEntities);
6: db.LoadOptions = options;
Diese Variante nutzen wir fast überall, allerdings haben wir zum Teil den Wunsch die Daten der Child-Entities einzuschränken. LoadWith würde alle verknüpften Elemente sofort mit laden, manchmal benötigt man nur einen bestimmten Teil der Daten. Somit macht es aus dem Performance-Gesichtspunkt und der Ressourcen-Optimierung viel Sinn nur die erforderlichen Daten zu laden. Durch AssociateWith kann man eine Einschränkung für das Laden der Daten definieren.
1: var query = from m in db.ChildEntities
2: select m;
3: var options = new DataLoadOptions();
4: options.AssociateWith<ChildEntities>(m=>m.ChildChildEntity.Where(c=c.Date > DateTime.UtcNow.AddDays(-60)));
5: options.LoadWith<ChildEntities>(m=>m.ParentEntity);
6: options.LoadWith<ChildEntities>(m=>m.ChildChildEntities);
7: db.LoadOptions = options;
Wie schon gesagt, kann man auf die LoadWith definition verzichten, in dem Fall hätte man das Lazy Loading eingeschränkt. Eine super Einführung in Linq To Sql Eager/Lazy Loading hat Hilton Giesenow in seinem Blog geschrieben.
Nun kam aber der zweite Teil der etwas Tricky war. Wir wollten nun mehrere Einschränkungen setzen. Eigentlich eine typische “In” Anweisung in einem SQL-Statement. Bei uns scheiterten die Versuche immer wieder, da half nur noch alles einen Tag liegen zu lassen und nächsten Tag sich das Problem noch mal anzuschauen. Schließlich muss es gehen, wir haben in Anfragen bereits an anderen Stellen mit Linq To Sql ausgeführt. Letztendlich hat uns der “Suchanbieter unseres Vertrauens” (Google) zu der Lösung des Problems geführt. John Liu hatte ein ähnliches Problem und es einfach in einem kurzen Beispiel dargestellt. Man darf nicht mit IList bei der Übergabe arbeiten, sondern muss IEnumerable-Interface nutzen.
1: var query = from m in db.ChildEntities
2: select m;
3: var options = new DataLoadOptions();
4: options.AssociateWith<ChildEntities>(m=>en.Contains(m.ChildChildEntity.Date));
5: options.LoadWith<ChildEntities>(m=>m.ParentEntity);
6: options.LoadWith<ChildEntities>(m=>m.ChildChildEntities);
7: db.LoadOptions = options;
Ich habe gestern Abend mal versucht eine Umwandlung der Statements in Linq To Entities gegoogled. Am Besten waren die Anweisungen auf dem ADO.NET-Team Blog, leider habe ich für die AssociateWith-Anweisung aber keine Entsprechung gefunden.