Я использую IRepository правильно?

Я надеюсь использовать шаблон IRepository (поддержанный NHibernate, если он имеет значение) в маленьком проекте. Домен является простым, намеренно так, чтобы позволить мне фокусироваться на понимании шаблона IRepository. Одинокий доменный класс 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) { ... }
}

Я должен был бы добавить необходимую реализацию к базовому классу, а также конкретному, с помощью NHibernate, но я хотел бы знать, на правильном пути ли я с этой установкой.

Кажется, существует немного издержек всего для одного доменного класса, хотя было бы менее примечательно, если бы было несколько доменных включенных классов. Прямо сейчас я пытаюсь сохранить это простым, таким образом, я могу придавить понятие.

12
задан Grant Palin 31 July 2010 в 19:02
поделиться

3 ответа

Я бы сказал, вы близки к репозиторию, который я использую в производственном решении для планирования ресурсов в транспортных компаниях. (также используя NHibernate) - так что для начала, на мой взгляд, вы на правильном пути. Я согласен с dbones на использование IEnumerables / IList вместо массивов - вы в конечном итоге напишете .ToArray () много раз :-).

Несколько вещей, которые вы могли бы рассмотреть:

Предпочитайте композицию наследованию - вместо наследования из абстрактного репозитория - пусть она будет не абстрактной, и вставьте ее в 'ctor и делегируйте вызовы - это сделает ваш дизайн более надежным в определенных ситуациях (например, для репозитория только для запросов и т. д.). Таким образом, у вас также есть возможность разрешить создание экземпляров абстрактного репозитория (это слово?) и контролировать, должен ли он использоваться во всех репозиториях.

В продолжение этого пункта - вы можете захотеть изменить базовый репозиторий, чтобы иметь общие методы вместо наследования от универсального интерфейса:

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, если что-то пойдет не так, и, возможно, выходной IEnumerable для любых ошибок, которые будут иметь смысл в вызывающем коде.

Но в целом - это всего лишь мои лакомые кусочки, которые я добавил со временем, чтобы лучше соответствовать моему использованию - и они совершенно необязательны, просто пища для размышлений :-). Думаю, вы на правильном пути - я не вижу серьезных проблем в вашем коде.

Надеюсь, это имеет смысл: -)

2
ответ дан 2 December 2019 в 22:51
поделиться
  1. постарайтесь не передавать обратно массив . используйте IEnumerable , ICollection или IList , это еще больше ослабит ваш код.

  2. ваш интерфейс IMovieRepository. этот репозиторий включает CRUD. поэтому сделайте это

IMovieRepository: IRepository {}

Это не изменит ваш класс MovieRepository , так как это будет правильно реализовывать интерфейс. это позволит вам отделить классы, если вы захотите изменить реализацию позже.

наконец. это нормально для одного из методов. поскольку у вас есть специализированная функциональность, вы настроили репозиторий в соответствии с требованиями.

есть и другие способы, которые позволяют использовать 1 класс репозитория и передавать требуемый запрос. Это называется шаблоном спецификации. Я сделал проект, который использует это, расположенное на codeplex, с отчетом http://whiteboardchat.codeplex.com

, иначе можно было бы получить метод для передачи критериев. есть проект с открытым исходным кодом под названием Sharp Architecture, в котором, как мне кажется, это закодировано.

Надеюсь, это поможет

6
ответ дан 2 December 2019 в 22:51
поделиться

В качестве пищи для размышлений, если ваш ORM по выбору имеет поставщика LINQ (а у NH есть один), вы можете попробовать запросить репозиторий, который очень похож на коллекцию:

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

Я написал кое-что об этом на моем сайте: Репозиторий или DAO ?: Репозиторий Он имеет сходство с вашей конструкцией (просто потому, что коллекция также поддерживает CRUD), подход, который я пробую, означает, что у вас может быть код, который не обязательно знает о работе с репозиторием, поскольку его можно запрограммировать на ICollection или интерфейс IQueryable ...

0
ответ дан 2 December 2019 в 22:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: