2008-10-02 13 views
27

Estoy considerando una de las dos interfaces de IRepository, una que es un descendiente de IQueryable y otra que contiene IQueryable.¿Deben los repositorios implementar IQueryable <T>?

De esta manera:

public interface IRepository<T> : IQueryable<T> 
{ 
    T Save(T entity); 
    void Delete(T entity); 
} 

O esto:

public interface IRepository<T> 
{ 
    T Save(T entity); 
    void Delete(T entity); 
    IQueryable<T> Query(); 
} 

uso de LINQ sería:

from dos 
in ServiceLocator.Current.GetInstance<IRepository<DomainObject>>() 
where dos.Id == id 
select dos 

O ...

from dos 
in ServiceLocator.Current.GetInstance<IRepository<DomainObject>>().Query 
where dos.Id == id 
select dos 

Me gusta un poco el primero, pero es problemático burlarse. ¿Cómo han implementado otras personas repositorios de LINQable, mockable?

+0

sólo para confirmar?Si regresa ** ** todas las entidades en 'Query()' y luego usar LINQ en su código de consumo para hacer una búsqueda, lo haría perezoso carga correcta? En realidad, ¿no cargaría miles de registros y luego los buscaría en su código de consumo? – gideon

+0

@giddy eso es correcto. – Rodi

Respuesta

14

Depende de si quiere una relación Has-A o Is-A.

La primera es una relación Is-A. La interfaz de IRepository es una interfaz IQueryable. El segundo es un has-a. El IRepository tiene una interfaz IQueryable. En el proceso de escribir esto, realmente me gusta el segundo mejor que el primero, simplemente porque cuando uso su segundo IRepository, puedo darle al método Query() CUALQUIER COSA que devuelva IQueryable. Para mí, eso es más flexible que la primera implementación.

+0

Esto es lo que terminé haciendo .. Ejemplo 1 El imitar es muy doloroso, con Moq de todos modos. –

+0

pregunta relacionada, estoy usando Moq para burlarse de un repositorio como en el Ejemplo 2, pero mi consulta contiene la lógica de asignación en el "nuevo seleccione {...}" que nunca se probó, porque la ejecución se aplaza hasta IRepository.Save(), que es burlado y nunca realiza el mapeo. ¿Algunas ideas? – flipdoubt

0

Siempre se puede escribir rápidamente cosas contra List, no se burla utilizando un marco simulado, pero funciona muy bien.

8

Personalmente, yo uso el Repository Pattern para devolver todos los elementos del repositorio como un IQueryable. Al hacer esto, mi capa de repositorio ahora es muy, muy pequeña, pequeña ... con la capa de servicio (que consume la capa Repositorio) ahora puede abrirse a todos los tipos de manipulación de consultas.

Básicamente, toda mi lógica ahora se encuentra en la capa de servicio (que no tiene idea de qué tipo de repositorio se utilizará ... y no quiere saber < - separación de preocupaciones) .. mientras mi capa de repositorio solo se trata de Obtener datos y Guardar datos en el repositorio (un servidor SQL, un archivo, un satélite en el espacio ... etc. < - más separación de preocupaciones).

por ejemplo. Más o menos código pseduo como yo estoy recordando lo que hemos hecho en nuestro código y simplificar todo por esta respuesta ...

public interface IRepository<T> 
{ 
    IQueryable<T> Find(); 
    void Save(T entity); 
    void Delete(T entity); 
} 

y tener un repositorio de usuarios ...

public class UserRepository : IRepository<User> 
{ 
    public IQueryable<User> Find() 
    { 
     // Context is some Entity Framework context or 
     // Linq-to-Sql or NHib or an Xml file, etc... 
     // I didn't bother adding this, to this example code. 
     return context.Users().AsQueryable(); 
    } 

    // ... etc 
} 

y ahora para el mejor poco :)

public void UserServices : IUserServices 
{ 
    private readonly IRepository<User> _userRepository; 

    public UserServices(IRepository<User> userRepository) 
    { 
     _userRepository = userRepository; 
    } 

    public User FindById(int userId) 
    { 
     return _userRepository.Find() 
      .WithUserId(userId) 
      .SingleOrDefault(); // <-- This will be null, if the 
           //  user doesn't exist 
           //  in the repository. 
    } 

    // Note: some people might not want the FindBySingle method because this 
    //  uber method can do that, also. But i wanted to show u the power 
    //  of having the Repository return an IQuerable. 
    public User FindSingle(Expression<Func<User, bool>> predicate) 
    { 
     return _userRepository 
      .Find() 
      .SingleOrDefault(predicate); 
    } 
} 

de Puntos adicionales: WTF es WithUserId(userId) en el método FindById? Eso es un Pipe and Filter. Úsalos :) les encanta :) abrázalos :) hacen que tu código sea MUY legible :) Ahora, si quieres saber qué es lo que hace ... este es el método de extensión.

public static User WithId(this IQueryable<User> source, int userId) 
{ 
    return source.Where(u => u.UserId == userId).SingleOrDefault(); 
} 

HTH a pesar de esta pregunta es .. bueno ... casi dos años :)

+1

me gusta la punta de los tubos y filtros – LamonteCristo

Cuestiones relacionadas