Shared repositories in repository pattern

走远了吗. 提交于 2019-12-13 12:09:19

问题


Repository dependency? Lets say I have a domain that looks like the following:

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

A user with my posts.

How do I set up my repository so that for every user, it returns a list of Post and for every post, I get the Poster?

I have 2 repositories:

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

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

I tried calling from 1 repository to the other, but it ends up in a crash because there is a circular dependency.

I'm using the POCO method of the repository pattern with entity framework.


回答1:


I have 2 repositories:

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

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

This is likely to become problematic.

You likely don't want to simply GetUsers. As you say, you want child entities loaded with the aggregate, or top-level, entity.

What will occur is that depending on the context of use - what your immediate purpose is - you will want variations on that User. You'll likely end up with methods like GetUsers, 'GetUsersWithPosts, GetUsersForImportantReport, GetUsersForAttendingAnIceCreamSocial, etc., etc., ad nauseam.

What's missing is the concept of a role.

What role are you retrieving the User for? Model that explicitly here.

Start with a base interface for your aggregate. Basic properties can go here

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

Add interfaces to support the roles in which you will use the user.

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

And your repository can be defined as such:

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

Now, use that role to define a fetching strategy;

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

Your repository would get the fetching strategies through injection or service location and call fetch. You can pass the repository in to provide the mechanism for the FetchingStrategy to query or have the FetchingStrategy inject or locate what services it needs to query.

Of course, exactly how you query will depend on your ORM.

But this way of modeling will help avoid many problems with loading entity graphs in different scenarios.




回答2:


IMHO, this belongs in the service layer, not the repository layer. Repository just wraps the DB.

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

...add security concerns, aggregation, etc, as needed.



来源:https://stackoverflow.com/questions/4628046/shared-repositories-in-repository-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!