2008-10-02 5 views
27

Je considère l'une des deux interfaces IRepository, une qui est un descendant de IQueryable et une qui contient IQueryable.Les référentiels doivent-ils implémenter IQueryable <T>?

Comme ceci:

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

Ou ceci:

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

utilisation de LINQ serait:

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

Ou ...

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

J'aime un peu le premier, mais il est problématique de se moquer. Comment d'autres personnes ont-elles implémenté LINQable, des référentiels simulables?

+0

Juste pour confirmer?Si vous renvoyez ** toutes ** les entités dans 'Query()', puis utilisez linq dans votre code consommateur pour faire une recherche, ce serait un chargement paresseux? Il ne chargerait pas réellement des milliers d'enregistrements, puis les rechercher dans votre code consommateur? – gideon

+0

@giddy c'est correct. – Rodi

Répondre

14

Dépend si vous voulez une relation Has-A ou Is-A.

La première est une relation Is-A. L'interface IRepository est une interface IQueryable. Le second est un has-a. L'IRepository a une interface IQueryable. En cours d'écriture ceci, j'aime réellement le second mieux que le premier, simplement parce que quand vous utilisez votre deuxième IRepository, je peux donner la méthode QUERY() à n'importe quel qui retourne IQueryable. Pour moi, c'est plus souple que la première mise en œuvre.

+0

C'est ce que j'ai fini par faire ... L'exemple 1 de simulation est tout simplement trop douloureux, avec Moq de toute façon. –

+0

Question connexe, j'utilise Moq pour simuler un référentiel comme l'exemple 2, mais ma requête contient une logique de mappage dans "select new {...}" qui ne sera jamais testée car l'exécution est différée jusqu'à IRepository.Save(), est raillé et n'effectue jamais le mappage. Des idées? – flipdoubt

0

Vous pourriez toujours écrire rapidement des choses sur List, ce n'est pas moqueur en utilisant un cadre fictif, mais ça fonctionne bien.

8

Personnellement, j'utilise le Repository Pattern pour renvoyer tous les éléments du référentiel en tant que IQueryable. En faisant cela, ma couche de dépôt est maintenant très très légère, petite .. avec la couche de service (qui consomme la couche Repository) peut maintenant être ouverte à tous les types de manipulation de requête. Fondamentalement, toute ma logique se trouve maintenant dans la couche de service (qui n'a aucune idée du type de référentiel qu'il utilisera .. et ne veut pas savoir < - séparation des préoccupations) .. alors que ma couche de dépôt est juste de traiter avec l'obtention de données et l'enregistrement des données au repo (un serveur sql, un fichier, un satellite dans l'espace .. etc < - plus de séparation des préoccupations).

par ex. Plus ou moins code pseduo que je me souviens de ce que nous avons fait dans notre code et la simplification pour cette réponse ...

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

et d'avoir un référentiel utilisateur ...

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 
} 

et maintenant le meilleur morceau :)

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

Points Bonus: WTF est WithUserId(userId) dans la méthode FindById? C'est un Pipe and Filter. Utilisez les :) les aimer :) les serrer :) Ils font votre code SOOO beaucoup lisible :) Maintenant, si vous voulez savoir ce que cela fait .. c'est la méthode d'extension.

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

HTH de même si cette question est .. bien ... près de deux ans :)

+1

J'aime la pointe sur les tuyaux et les filtres – LamonteCristo

Questions connexes