2011-01-07 5 views
3

Dépendance du référentiel? Disons que j'ai un domaine qui ressemble à ce qui suit:Référentiels partagés dans le modèle de référentiel

public class User 
{ 
    public int UserId { get; set; } 
    public Lazy<Post> Posts { get; set; } 
} 

public class Post 
{ 
    public int PostId { get; set; } 
    public User Poster { get; set; } 
} 

Un utilisateur avec mes messages.

Comment puis-je configurer mon dépôt de telle sorte que pour chaque user, il retourne une liste de Post et pour chaque post, je reçois le Poster?

J'ai 2 dépôts:

public class UserRepository : IUserRepository 
{ 
    public IQueryable<User> GetUsers(); 
} 

public class PostRepository : IPostRepository 
{ 
    public IQueryable<Post> GetPosts(); 
} 

J'ai essayé d'appeler de 1 référentiel à l'autre, mais il finit dans un accident parce qu'il ya une dépendance circulaire.

J'utilise la méthode POCO du modèle de référentiel avec structure d'entité.

+0

Qu'est-ce que vous utilisez pour votre ORM? NHibernate, Entity Framework ou autre chose. Cela nous aidera à vous donner une meilleure réponse. – ilivewithian

+0

@ilivewithian EF4. –

Répondre

1

J'ai 2 dépôts:

public class UserRepository : IUserRepository 
{ 
    public IQueryable<User> GetUsers(); 
} 

public class PostRepository : IPostRepository 
{ 
    public IQueryable<Post> GetPosts(); 
} 

Ceci est susceptible de devenir problématique.

Vous ne voulez probablement pas simplement GetUsers. Comme vous le dites, vous voulez que les entités enfants soient chargées avec l'entité agrégée ou de niveau supérieur. Ce qui se passera est que, selon le contexte d'utilisation - quel est votre but immédiat - vous voulez des variations sur ce User. Vous finirez probablement avec des méthodes comme GetUsers, 'GetUsersWithPosts, GetUsersForImportantReport, GetUsersForAttendingAnIceCreamSocial, etc., etc., ad nauseam.

Ce qui manque, c'est le concept d'un rôle.

Pour quel rôle récupérez-vous l'utilisateur? Modélisez cela explicitement ici.

Commencez avec une interface de base pour votre agrégat. Propriétés de base peuvent aller ici

public interface IUser { 
    public Guid UserId { get; set; } 
    public string UserName { get; set; } 
    public IEnumerable<Posts> { get; set; } 
} 

Ajoutez des interfaces pour prendre en charge les rôles dans lesquels vous utiliserez l'utilisateur.

public interface IAddPostsToUser : IUser { 
    public void AddPost(Post post); 
} 

Et votre dépôt peut être défini comme tel:

public interface IUserRepository { 
    User Get<TRole>(Guid userId) where TRole : IUser; 
} 

Maintenant, utilisez ce rôle pour définir une stratégie de récupération;

public interface IFetchingStrategy<TRole> { 
    TRole Fetch(Guid id, IRepository<TRole> role) 
} 

Votre référentiel obtiendrait les stratégies de récupération via l'emplacement d'injection ou de service et l'extraction d'appel.Vous pouvez transmettre le référentiel pour fournir le mécanisme d'interrogation de FetchingStrategy ou demander à FetchingStrategy d'injecter ou de localiser les services dont il a besoin pour interroger.

Bien sûr, la façon dont vous interrogez dépend de votre ORM. Mais cette manière de modéliser permettra d'éviter de nombreux problèmes de chargement de graphes d'entité dans différents scénarios.

+0

Udi Dahan a un diaporama sur les concepts: http://cid-c8ad44874742a74d.skydrive.live.com/self.aspx/Blog/Intentions%20and%20Interfaces.pdf –

+0

Connaissez-vous un exemple de projet utilisant ce modèle? avec un cadre d'entité? –

+0

Je ne sais pas. Mais je pense que j'exposerais peut-être le contexte en tant que propriété interne dans les implémentations du référentiel *, et que l'implémentation de FetchingStrategy transtendrait l'interface du Repository sur l'implémentation concrète. et obtenir ce contexte pour effectuer des requêtes. Cela devrait vraiment aller de pair. –

-1

À mon humble avis, cela appartient à la couche de service, pas à la couche de référentiel. Le référentiel enveloppe simplement la base de données.

public IQueryable<UserData> GetUsersWithPosts() 
{ 
    return from u in UserRepository.GetUsers() 
      select new UserData 
      { 
       Id = u.Id, 
       Name = u.Name 
       Posts = from p in u.Posts 
         select new PostData 
         { 
          Id = u.Id, 
          Title = p.Title 
         } 
      }; 

... ajouter des problèmes de sécurité, l'agrégation, etc., au besoin.

+0

Cela signifie que chaque fois que je reçois un message, je dois réécrire une conversion de ORMDomain à mon domaine en raison de POCO. –

+0

AutoMapper rend cela un peu plus facile, pas que je recommande cette route de toute façon –

+0

@Shawn, non, ça ne veut pas dire ça. J'ai juste choisi de montrer ce que je pense être la bonne façon de le faire. L'aspect essentiel de la mise au point des préoccupations des entreprises dans le service et la conservation des dépôts n'est pas modifié, que vous utilisiez la projection, l'extraction de stratégies, le chargement explicitement volontaire ou toute autre approche. @qstarin, AutoMapper ne comprend pas 'IQueryable ' et n'est pas un outil approprié pour cela. –

Questions connexes