2009-08-21 11 views
6

Ho due domande relative a Linq to SQL. Si prega di vedere l'immagine qui sotto per vedere come appare il mio modello.Eager caricamento di Linq in entità SQL in una tabella autoreferenziale

Domanda 1

Sto cercando di capire come caricare il campo User.AddedByUser sul mio User classe/tavolo ansioso. Questo campo è generato dalla relazione nel campo User.AddedByUserId. La tabella è auto-referenziale e sto cercando di capire come ottenere Linq su SQL per caricare la proprietà User.AddedByUser in modo avido, cioè ogni volta che qualsiasi entità User viene caricata/recuperata, deve anche recuperare User.AddedByUser e User.ChangedByUser . Tuttavia, ho capito che questo potrebbe diventare un problema ricorsivo ...

Update 1.1:

Ho cercato di utilizzare i DataLoadOptions come segue:

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

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

ma questo non lavoro, ottengo la seguente eccezione sulla linea 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: 

l'eccezione è abbastanza auto-esplicativo - l'oggetto grafico non è permesso essere ciclico. Inoltre, supponendo che la Linea 2 non abbia generato un'eccezione, sono abbastanza sicuro che la Linea 3 sarebbe, dal momento che sono chiavi duplicate.

Update 1.2:

La seguente non funziona neanche (non utilizzato in combinazione con Update 1.1 sopra):

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

Esso genera la seguente, salvo auto-esplicativo:

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

Ora sono VERAMENTE in perdita su come risolvere questo. Per favore aiuto!

Domanda 2

Su ogni altra tavola nel mio DB, e quindi LINQ to modello SQL, ho due campi, Entity.ChangedByUser (legato alla Entity.ChangedByUserId chiave esterna/rapporto) e Entity.AddedByUser (legato al Entity.AddedByUserId chiave esterna/relazione)

Come faccio a ottenere da Linq SQL il carico di questi campi per me? Devo fare un semplice join sulle mie query? O c'è un altro modo?

Linq to SQL eager loading on self referencing table http://img245.imageshack.us/img245/5631/linqtosql.jpg

risposta

3

Forse potresti provare a fare un passo indietro e vedere cosa vuoi fare do con la relazione? Suppongo che tu voglia visualizzare queste informazioni all'utente in es. "modificato da Iain Galloway 8 ore fa".

Potrebbe qualcosa come il seguente lavoro? : -

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

Ho usato un tipo anonimo per (imo) chiarezza. Potresti aggiungere tali proprietà al tuo tipo di utente, se preferisci.

Per quanto riguarda la seconda domanda, il tuo LoadWith normale (x => x.AddedByUser) ecc. Dovrebbe funzionare bene - sebbene io tendo a preferire la memorizzazione della stringa di descrizione direttamente nel database - hai un trade-off tra l'aggiornamento della descrizione quando ChangedByUser.FullName cambia e deve fare qualcosa di complicato e possibilmente controintuitivo se ChangedByUser viene cancellato (es. ON DELETE CASCADE, o che ha a che fare con un ChangedByUser nullo nel codice).

+0

Sì, desidero visualizzare tali informazioni nella GUI. Speravo di risolvere questo problema senza l'uso di tipi anonimi. Ma immagino che sia un modo per risolvere il problema. Il mio problema è legato all'impossibilità da parte di Linq di SQL di far fronte a molte e molte relazioni? –

+0

Na, è possibile aggiungere i campi User.AddedDescription e User.ChangedDescription alla classe User e quindi non si dovrà utilizzare un tipo anon. Non ha davvero niente a che fare con la relazione molti-molti (ogni relazione nel tuo esempio è 1: 1). Se scriveste direttamente il vostro SQL, non vorreste ottenere tutte le proprietà di AddedByUser (incluso il suo AddedByUser e così via in infinito). Probabilmente ti basta prendere il suo nome e/o qualsiasi altro dettaglio che ti serva per la tua visione. Imo è un problema O/RM più generale. Penso che avresti lo stesso problema con L2E o Hibernate. –

0

Non che ci sia una soluzione a questo problema con LINQ to SQL. Se si sta utilizzando Sql Server 2005, è possibile definire un processo memorizzato (ricorsivo come) che utilizza espressioni di tabella comuni per ottenere il risultato desiderato e quindi eseguirlo utilizzando DataContext.ExecuteQuery.

4

Any type of cycles just aren't allowed. Poiché lo LoadWith<T> o AssociateWith<T> vengono applicati a ogni tipo nel contesto, non esiste un modo interno per impedire un ciclo infinito. Più precisamente, è solo confuso su come creare l'SQL dal momento che SQL Server non ha CONNECT BY e CTEs sono davvero passati a ciò che Linq può generare automaticamente con il framework fornito.

L'opzione migliore disponibile è quella di eseguire manualmente il join di 1 livello nella tabella utente per entrambi i bambini e un tipo anonimo per restituirli. Spiacente, non è una soluzione pulita/facile, ma è davvero tutto ciò che è disponibile finora con Linq.

Problemi correlati