2009-08-21 8 views
6

J'ai deux questions liées Linq à SQL. S'il vous plaît voir l'image ci-dessous pour voir à quoi ressemble mon modèle.Mise en attente du chargement de Linq vers des entités SQL dans une table auto-référencée

Question 1

J'essaie de comprendre comment désireux charge le champ User.AddedByUser sur ma User classe/table. Ce champ est généré à partir de la relation sur le champ User.AddedByUserId. La table est auto-référencée, et j'essaie de comprendre comment obtenir Linq to SQL pour charger la propriété User.AddedByUser avec impatience, c'est à dire chaque fois qu'une entité User est chargée/récupérée, elle doit également récupérer User.AddedByUser et User.ChangedByUser . Cependant, je comprends que cela pourrait devenir un problème récurrent ...

Mise à jour 1.1:

J'ai essayé d'utiliser les DataLoadOptions comme suit:

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

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

Mais cela ne travail, je reçois l'exception suivante sur la ligne 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'exception est tout à fait explicite - le graphe d'objet n'est pas autorisé être cyclique. En outre, en supposant que la ligne 2 ne lève pas une exception, je suis assez sûr que la ligne 3 le ferait, car ce sont des clés dupliquées.

Mise à jour 1.2:

Ce qui suit ne fonctionne pas non plus (non utilisé conjointement avec Update 1.1 ci-dessus):

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

Il jette ce qui suit, exception explicite:

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

Maintenant, je ne sais vraiment pas comment résoudre ce problème. S'il vous plaît aider!

Question 2

Sur tous les autres table dans mon DB, et donc Linq au modèle SQL, j'ai deux champs, Entity.ChangedByUser (lié à Entity.ChangedByUserId clé/relation étrangère) et Entity.AddedByUser (liée à Entity.AddedByUserId clé étrangère/relation)

Comment puis-je charger Linq to SQL pour charger ces champs avec impatience pour moi? Ai-je besoin de faire une simple jointure sur mes requêtes? Ou existe-t-il un autre moyen?

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

Répondre

3

Peut-être que vous pourriez essayer de prendre du recul et de voir ce que vous voulez faire avec la relation? Je suppose que vous voulez afficher cette information à l'utilisateur par exemple. "modifié par Iain Galloway il y a 8 heures".

Une chose du genre avec les suivantes? : -

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

J'ai utilisé un type anonyme pour la clarté (imo). Vous pouvez ajouter ces propriétés à votre type d'utilisateur si vous le souhaitez. En ce qui concerne votre deuxième question, votre LoadWith normal (x => x.AddedByUser) etc. devrait fonctionner correctement - bien que j'ai tendance à préférer stocker la chaîne de description directement dans la base de données - vous avez un compromis entre votre description de mise à jour lorsque ChangedByUser.FullName change et d'avoir à faire quelque chose de compliqué et éventuellement contre-intuitif si le ChangedByUser est supprimé (par exemple ON DELETE CASCADE, ou traiter un null ChangedByUser dans votre code).

+0

Oui, je souhaite afficher cette information dans mon interface graphique. J'espérais résoudre ce problème sans l'utilisation de types anonymes. Mais je suppose que c'est une façon de résoudre le problème. Est-ce que mon problème est lié à l'incapacité de Linq à SQL de faire face à de nombreuses relations? –

+0

Na, vous pouvez ajouter des champs User.AddedDescription et User.ChangedDescription à la classe User, puis vous ne devrez pas utiliser un type anon. Ce n'est pas vraiment quelque chose à voir avec la relation many-many (chaque relation dans votre exemple est 1: 1). Si vous écriviez votre SQL directement, vous ne voudriez pas obtenir toutes les propriétés de l'AddedByUser (y compris son AddedByUser et ainsi de suite dans l'infini). Vous devrez probablement saisir son nom et/ou tous les détails dont vous avez besoin pour votre vue. Imo c'est un problème O/RM plus général. Je pense que vous auriez le même problème avec L2E ou Hibernate. –

0

pas sûr qu'il ya une solution à ce problème avec LINQ to SQL. Si vous utilisez Sql Server 2005, vous pouvez définir une Procecdure stockée (récursive) qui utilise des expressions de table communes pour obtenir le résultat souhaité, puis l'exécuter à l'aide de DataContext.ExecuteQuery.

4

Any type of cycles just aren't allowed. Puisque le LoadWith<T> ou AssociateWith<T> sont appliqués à chaque type sur le contexte, il n'y a aucun moyen interne d'empêcher une boucle sans fin. Plus précisément, il est juste confus sur la façon de créer le SQL puisque SQL Server n'a pas CONNECT BY et CTEs sont vraiment passé ce que Linq peut générer automatiquement avec le cadre fourni.

La meilleure option à votre disposition est de faire manuellement la jonction 1 niveau vers la table utilisateur pour les deux enfants et un type anonyme pour les renvoyer. Désolé, ce n'est pas une solution propre/facile, mais c'est vraiment tout ce qui est disponible jusqu'à maintenant avec Linq.

Questions connexes