Para mí, el patrón de repositorio consiste en poner una capa delgada alrededor de su metodología de acceso a datos. LINQ to SQL en su caso, pero NHibernate, hecho a mano en otros. Lo que me he encontrado haciendo es crear un repositorio por tabla, porque es extremadamente simple (como las listas de bruno y ya lo tienes). Esa es la responsable de encontrar cosas y hacer operaciones CRUD.
Pero luego tengo un nivel de servicio que se ocupa más de las raíces agregadas, como menciona Johannes. Tendría un UserService con un método como GetExistingUser (int id). Esto llamaría internamente al método UserRepository.GetById() para recuperar al usuario. Si su proceso empresarial requiere que la clase de usuario devuelta por GetExistingUser() casi siempre necesite que se llene la propiedad User.IsInRoles(), simplemente haga que UserService dependa del UserRepository y RoleRepository. En pseudo código podría ser algo como esto:
public class UserService
{
public UserService(IUserRepository userRep, IRoleRepository roleRep) {...}
public User GetById(int id)
{
User user = _userService.GetById(id);
user.Roles = _roleService.FindByUser(id);
return user;
}
El userRep y roleRep se construirían con su LINQ a SQL bits de algo como esto:
public class UserRep : IUserRepository
{
public UserRep(string connectionStringName)
{
// user the conn when building your datacontext
}
public User GetById(int id)
{
var context = new DataContext(_conString);
// obviously typing this freeform but you get the idea...
var user = // linq stuff
return user;
}
public IQueryable<User> FindAll()
{
var context = // ... same pattern, delayed execution
}
}
Personalmente haría que las clases de repositorios de ámbito interno y tiene el UserService y otras clases XXXXXService públicas, así que mantenga honestos a los consumidores de la API del servicio. Así que, de nuevo, veo que los repositorios están más estrechamente relacionados con el hecho de hablar con un almacén de datos, pero su capa de servicio está más alineada con las necesidades de su proceso comercial.
A menudo me he encontrado pensando demasiado en la flexibilidad de Linq para objetos y todo eso y usando IQuerable y otros en lugar de simplemente crear métodos de servicio que escuchan lo que realmente necesito.User LINQ donde sea apropiado, pero no intente hacer que el repositorio haga todo.
public IList<User> ActiveUsersInRole(Role role)
{
var users = _userRep.FindAll(); // IQueryable<User>() - delayed execution;
var activeUsersInRole = from users u where u.IsActive = true && u.Role.Contains(role);
// I can't remember any linq and i'm type pseudocode, but
// again the point is that the service is presenting a simple
// interface and delegating responsibility to
// the repository with it's simple methods.
return activeUsersInRole;
}
Así que, eso fue un poco divagante. No estoy seguro de si realmente ayudé a alguno, pero mi consejo es evitar ser demasiado sofisticado con los métodos de extensión, y simplemente agregar otra capa para mantener cada una de las partes móviles bastante simple. Funciona para mi.
Bueno, ahí tienes. Aprende algo todos los días. Tendré que ajustar mi propio enfoque :-) – Dylan
Sí. También aprendo algo con esta respuesta. Sabía que era lógico tener varios repositorios, pero no sabía que cada repositorio debería construirse alrededor de agregados. Tiene sentido total –
Excelente publicación. –