代码之家  ›  专栏  ›  技术社区  ›  Andy S

存储库是否应实现IQueryable?

  •  27
  • Andy S  · 技术社区  · 16 年前

    我正在考虑两个IRepository接口中的一个,一个是IQueryable的后代,另一个包含IQueryable。

    这样地:

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

    或者:

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

    LINQ的用法是:

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

    或者…

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

    我有点喜欢第一个,但嘲笑是有问题的。其他人是如何实现Linqable、Mockable存储库的?

    3 回复  |  直到 14 年前
        1
  •  14
  •   MagicKat    16 年前

    这取决于你是想要一段“有”还是“是”的关系。

    第一个是“是-是”关系。iRepository接口是一个iQuery接口。第二个是HAS-A。iRepository有一个IQueryable接口。在编写这个过程中,我实际上更喜欢第二个方法,而不是第一个,因为当使用第二个iRepository时,我可以为query()方法提供返回iQuery的任何内容。对我来说,这比第一个实现更灵活。

        2
  •  8
  •   Pure.Krome    14 年前

    就个人而言,我使用 Repository Pattern 将存储库中的所有项目作为 IQueryable .通过这样做,我的存储库层现在非常轻,很小。通过服务层(使用存储库层),现在可以对所有类型的查询操作开放。

    基本上,我的所有逻辑现在都位于服务层中(不知道它将使用哪种类型的存储库)。并且不想知道<——关注点分离)。虽然我的存储库层只是处理获取数据并将数据保存到repo(一个SQL服务器、一个文件、一个空间卫星)。等等——更多的关注点分离)。

    或多或少是psedo代码,因为我记得我们在代码中做了些什么,并简化了这个答案…

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

    拥有一个用户存储库…

    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
    }
    

    现在为了最好的一点:)

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

    奖励积分:WTF为 WithUserId(userId) FindById 方法?那是一个 Pipe and Filter . 使用它们:)爱它们:)拥抱它们:)它们让你的代码很容易阅读:)现在,如果你想知道它的作用。这是扩展方法。

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

    尽管这个问题是……好。。。差不多两岁了:)

        3
  •  0
  •   Kim Johansson    16 年前

    你可以随时根据列表快速地写东西,这不是使用模拟框架进行模拟,但它确实非常有效。