7 Stimmen

Eifriges Laden von Linq to SQL Entities in einer selbstreferenzierenden Tabelle

Ich habe 2 verwandte Linq to SQL Fragen. Bitte sehen Sie das Bild unten, um zu sehen, wie mein Modell aussieht.

Frage 1

Ich versuche herauszufinden, wie man die User.AddedByUser Feld auf meinem User Klasse/Tisch. Dieses Feld wird aus der Beziehung auf der Registerkarte User.AddedByUserId Bereich. Die Tabelle ist selbstreferenzierend, und ich versuche herauszufinden, wie ich Linq to SQL dazu bringe, die Tabelle zu laden. User.AddedByUser Eigenschaft eifrig, d.h. immer wenn eine User Entität geladen/abgeholt wird, muss es auch die User.AddedByUser und User.ChangedByUser abholen. Ich verstehe jedoch, dass dies ein rekursives Problem werden könnte...

Aktualisierung 1.1:

Ich habe versucht, die DataLoadOptions wie folgt zu verwenden:

var options = new DataLoadOptions();
options.LoadWith<User>(u => u.ChangedByUser);
options.LoadWith<User>(u => u.AddedByUser);

db = new ModelDataContext(connectionString);
db.LoadOptions = options;

Aber das funktioniert nicht, ich erhalte die folgende Ausnahme in Zeile 2:

System.InvalidOperationException occurred
  Message="Cycles not allowed in LoadOptions LoadWith type graph."
  Source="System.Data.Linq"
  StackTrace:
       at System.Data.Linq.DataLoadOptions.ValidateTypeGraphAcyclic()
       at System.Data.Linq.DataLoadOptions.Preload(MemberInfo association)
       at System.Data.Linq.DataLoadOptions.LoadWith[T](Expression`1 expression)
       at i3t.KpCosting.Service.Library.Repositories.UserRepository..ctor(String connectionString) in C:\Development\KP Costing\Trunk\Code\i3t.KpCosting.Service.Library\Repositories\UserRepository.cs:line 15
  InnerException:

Die Ausnahme ist ziemlich selbsterklärend - der Objektgraph darf nicht zyklisch sein. Wenn Zeile 2 keine Ausnahme auslöst, bin ich mir ziemlich sicher, dass dies auch bei Zeile 3 der Fall ist, da es sich um doppelte Schlüssel handelt.

Aktualisierung 1.2 :

Das folgende funktioniert ebenfalls nicht (nicht in Verbindung mit Aktualisierung 1.1 oben):

var query = from u in db.Users
            select new User()
            {
                Id = u.Id,
                // other fields removed for brevityy
                AddedByUser = u.AddedByUser,
                ChangedByUser = u.ChangedByUser,

            };
return query.ToList();

Er löst die folgende, selbsterklärende Ausnahme aus:

System.NotSupportedException occurred
Message="Explicit construction of entity type 'i3t.KpCosting.Shared.Model.User' in query is not allowed."

Ich bin jetzt wirklich ratlos, wie ich das Problem lösen kann. Bitte helfen Sie!

Frage 2

Auf jeder anderen Tabelle in meiner DB, und daher Linq to SQL-Modell, habe ich zwei Felder, Entity.ChangedByUser (verlinkt mit Entity.ChangedByUserId Fremdschlüssel/Verknüpfung) und Entity.AddedByUser (verlinkt mit Entity.AddedByUserId Fremdschlüssel/Verwandtschaft)

Wie bringe ich Linq to SQL dazu, diese Felder eifrig für mich zu laden? Muss ich eine einfache Verknüpfung meiner Abfragen durchführen oder gibt es eine andere Möglichkeit?

Eifriges Laden von Linq to SQL auf selbst referenzierende Tabellen http://img245.imageshack.us/img245/5631/linqtosql.jpg

4voto

Nick Craver Punkte 609016

Jede Art von Fahrrädern ist einfach nicht erlaubt . Da die LoadWith<T> o AssociateWith<T> auf jeden Typ im Kontext angewendet werden, gibt es keine interne Möglichkeit, eine Endlosschleife zu verhindern. Genauer gesagt, es ist einfach nur verwirrt, wie man das SQL erstellt, da SQL Server nicht über CONNECT BY y CTEs sind wirklich jenseits dessen, was Linq mit dem bereitgestellten Framework automatisch generieren kann.

Die beste Option, die Ihnen zur Verfügung steht, ist die manuelle Durchführung des 1-Level-Joins hinunter zur Benutzertabelle für beide Kinder und einen anonymen Typ, um sie zurückzugeben. Tut mir leid, es ist nicht eine saubere/einfache Lösung, aber es ist wirklich alles, was bisher mit Linq verfügbar ist.

3voto

Iain Galloway Punkte 17770

Vielleicht könnten Sie versuchen, einen Schritt zurückzutreten und zu sehen, was Sie wollen faire mit der Beziehung? Ich gehe davon aus, dass Sie dem Benutzer diese Informationen z. B. in der Form "geändert von Iain Galloway vor 8 Stunden" anzeigen möchten.

Könnte etwas wie das Folgende funktionieren? :-

var users = from u in db.Users
            select new
            {
              /* other stuff... */
              AddedTimestamp = u.AddedTimestamp,
              AddedDescription = u.AddedByUser.FullName,
              ChangedTimestamp = u.ChangedTimestamp,
              ChangedDescription = u.ChangedByUser.FullName
            };

Ich habe dort einen anonymen Typus verwendet, um (imo) Klarheit zu schaffen. Wenn Sie möchten, können Sie diese Eigenschaften zu Ihrem Benutzertyp hinzufügen.

Was Ihre zweite Frage betrifft, sollte Ihr normales LoadWith(x => x.AddedByUser) usw. gut funktionieren - obwohl ich dazu neige, die Beschreibungszeichenfolge direkt in der Datenbank zu speichern - Sie haben einen Kompromiss zwischen Ihrer Beschreibung, die aktualisiert wird, wenn sich ChangedByUser.FullName ändert, und etwas Kompliziertes und möglicherweise kontraintuitives zu tun, wenn der ChangedByUser gelöscht wird (z. B. ON DELETE CASCADE oder Umgang mit einem null ChangedByUser in Ihrem Code).

0 Stimmen

Ja, ich möchte diese Informationen in meiner GUI anzeigen. Ich hatte gehofft, dieses Problem ohne die Verwendung von anonymen Typen zu lösen. Aber ich denke, es ist eine Möglichkeit, das Problem zu lösen. Hängt mein Problem mit der Unfähigkeit von Linq to SQL zusammen, mit vielen zu vielen Beziehungen umzugehen?

0 Stimmen

Na, Sie könnten die Felder User.AddedDescription und User.ChangedDescription zur Klasse User hinzufügen und müssten dann keinen Anon-Typ verwenden. Es hat nicht wirklich etwas mit der Many-Many-Beziehung zu tun (jede Beziehung in Ihrem Beispiel ist 1:1). Wenn Sie Ihr SQL direkt schreiben würden, würden Sie nicht alle Eigenschaften des AddedByUser abrufen wollen (einschließlich seines AddedByUser und so weiter bis ins Unendliche). Sie würden wahrscheinlich nur seinen Namen und/oder die Details abrufen, die Sie für Ihre Ansicht benötigen. Imo ist es ein allgemeineres O/RM Problem. Ich denke, dass Sie das gleiche Problem mit L2E oder Hibernate haben würden.

0voto

Simon Fox Punkte 10249

Ich bin nicht sicher, ob es eine Lösung für dieses Problem mit Linq to Sql gibt. Wenn Sie Sql Server 2005 verwenden, könnten Sie eine (rekursive wie) Stored Procecdure definieren, die gemeinsame Tabellenausdrücke verwendet, um das gewünschte Ergebnis zu erhalten und dann ausführen, dass mit DataContext.ExecuteQuery.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X