代码之家  ›  专栏  ›  技术社区  ›  Grant Palin Bob King

我是否正确使用了IRepository?

  •  12
  • Grant Palin Bob King  · 技术社区  · 15 年前

    Movie ,具有的属性 Year , Genre Title

    公约似乎有一个通用的 IRepository 接口,类似于:

    public interface IRepository<T>
    {
        T Get(int id);
        T[] GetAll();
        void Add(T item);
        void Update(T item);
        void Delete(T item);
    }
    

    public abstract class Repository<T> : IRepository<T>
    {
        public T Get(int id) { ... }
        public T[] GetAll() { ... }
        public void Add(T item) { ... }
        public void Update(T item) { ... }
        public void Delete(T item) { ... }
    }
    

    然后要拥有特定于域的接口:

    public interface IMovieRepository
    {
        Movie[] GetByGenre(Genre genre);
        Movie[] GetByYear(int year);
        Movie[] GetByTitle(string title);
    }
    

    同时扩展了基础的实现 Repository 班级:

    public class MovieRepository : Repository<Movie>, IMovieRepository
    {
        public Movie[] GetByGenre(Genre genre) { ... }
        public Movie[] GetByYear(int year) { ... }
        public Movie[] GetByTitle(string title) { ... }
    }
    

    3 回复  |  直到 15 年前
        1
  •  2
  •   Goblin    15 年前

    我想说的是,您离我在运输公司的资源规划生产解决方案中使用的存储库很近(也使用NHibernate),所以对于初学者来说,我认为您走的是正确的道路。我同意dbones关于使用IEnumerables/IList而不是数组的观点-您最终会多次编写.ToArray():-)。

    您可以考虑以下几点:

    public class Repository
    {
        public void Add<T>(T entity)
        {
            using(var session = GetSession())
            using(var tx = session.BeginTransaction())
            {
                 session.Save(entity)
                 //Transaction handling etc.
            }
        }
        .... //repeat ad nasseum :-)
    }
    

    您可能希望让特定的存储库能够访问ISession—这大大提高了查询的灵活性,并可以控制急/慢抓取,还可以充分利用NHibernate等。

    public class Repository
    {
        public IList<T> WrapQueryInSession<T>(Func<ISession,IList<T> query)
        {
            using(var session = GetSession())
            using(var tx = session.BeginTransaction())
            {
                 var items = query(session);
                 //Handle exceptions transacitons etc.
                 return items;
            }
         }
     }
    

    用法:

    public class MovieRepository : IMovieRepository
    {
        private Repository _repository;
        public MovieRepository(Repository repository)
        {
            _repository = repository;
        }
        public IList<Movie> GetByYear(int year)
        {
            Func<ISession, IList<Movie> query = session =>
            {
                var query = session.CreateQuery("from Movie"); //or
                var query = session.CreateCriteria("from Movie"); //or
                var query = session.Linq<Movie>();
                //set criteria etc.
                return query.List<Movie>(); //ToList<Movie>() if you're using Linq2NHibernate
            }:
            return _repository.WrapQueryInSession(query);
        }
    }
    

    如果出现错误,您可能还需要在方法上设置bool返回值,并且可能需要为调用代码中有意义的任何错误设置out-IEnumerable。

    希望这有意义:-)

        2
  •  6
  •   dbones    15 年前
    1. 试着不要把一封信传回去 array . 使用 IEnumerable<T> , ICollection<T> IList<T> ,这将进一步松散地耦合代码。

    2. 您的IMovieRepository界面。这个存储库包括CRUD。因此,让它

    IMovieRepository : IRepository<Movie> {}

    这不会改变你的想法 MovieRepository

    最后。这对于其中一种方法来说是很好的。因为您拥有专门的功能,所以您已经专门化了存储库来适应。

    还有其他方法,使您能够使用1个存储库类并传入所需的查询。这称为规范模式。我做了一个项目,使用这个位于codeplex与报告 http://whiteboardchat.codeplex.com

    希望这有帮助

        3
  •  0
  •   flq    15 年前

    public interface IRepository<T> : ICollection<T>, IQueryable<T>
    

    我在我的网站上写了一些: Repository or DAO?: Repository 它与您的构造有相似之处(仅仅因为集合也支持CRUD),我尝试的方法意味着您可以拥有不一定知道如何处理存储库的代码,因为它可以根据 ICollection IQueryable 接口。。。

    推荐文章