NHibernate - Можно ли использовать абстрактную базу для обеспечения функциональности вместо интерфейса? - PullRequest
1 голос
/ 24 марта 2009

Я довольно новичок в NHibernate и столкнулся со странной проблемой цепочки наследования в моих классах репозитория. Я использовал FAQ Габриэля Шенкера в качестве справочного материала и, следуя его примерам, я создавал интерфейсы для определения контрактов для операций DAO в классах "репозитория". Схема данных, с которой я работаю, довольно обширна, и через некоторое время я обнаружил, что дублирую много кода. В частности, методы Add, Update, Delete и «GetByID» были точно такими же после того, как я добавил универсальный параметр «EntityType» в базовый интерфейс. Так, например, это будет самый простой интерфейс для операций с репозиторием:

public interface IBasicRepository<EntityType> where EntityType : class
{
    void Add(EntityType entity);
    void Remove(EntityType entity);
    void Update(EntityType entity);
    EntityType GetByID<IDType>(IDType id);
}

Теперь я буду просто говорить о методе Add для краткости. С универсальным EntityType реализации были одинаковыми:

public void Add(EntityType entity)
{
    using (ISession session = NHUtility.OpenSession())
    {
         using (ITransaction transaction = session.BeginTransaction())
         {
             session.Save(entity);
             transaction.Commit();
         }
    }
}

Очевидно, что многократный ввод текста одного и того же метода (с небольшим изменением типа) не только раздражает, это плохой дизайн в моей книге. Поэтому я создал абстрактный базовый класс, который я назову RepositoryBase, который обеспечивает реализацию для Add (). Поскольку вместо интерфейса я использую реферат, я «разрываю цепочку интерфейсов» для классов, унаследованных от RepositoryBase, и вынужден также делать любые деривации абстрактными, даже если использование интерфейса кажется более «правильным». Используя этот дерьмовый пример маленькой сущности ....

public class Entity1
{
    public Guid ID { get; set; }
    public String Name { get; set; }
}

... никто не может этого сделать ...

public interface IEntity1Repository : RepositoryBase<Entity1>
{
    //Illegal!!!!  Bad, naughty programmer!
}

... но это нормально ....

public abstract class Entity1RepositoryBase : RepositoryBase<Entity1>
{
    public abstract ICollection<Entity1> GetByName(string name);
}

Это меня просто беспокоит. Это работает, но это меня теряет, особенно потому, что цепочка наследования / реализации с этой конкретной схемой может идти довольно глубоко. Итак, я думаю, мои вопросы:

  1. Разве я просто глуп и сдерживаюсь по этому поводу?
  2. Есть ли другой / лучший дизайн, на который я должен смотреть здесь? Я рассмотрел некоторые другие примеры (в частности, Билли МакКафферти ), и подход Шенкера кажется самым простым для новичка в NHibernating.

Заранее спасибо.

1 Ответ

7 голосов
/ 24 марта 2009

Один из вариантов может быть:

public interface IRepository<T> where T: class
{
    void Add(T entity);
    void Remove(T entity);
    void Update(T entity);
    T GetByID<IDType>(IDType id);
}

С базовым классом, который реализует этот интерфейс. То есть:

public abstract class RepositoryBase<T> : IRepository<T> where T: class
{
    ...
}

Который затем расширяется для каждого типа сущности, если необходимо:

public interface IProductRepository :  IRepository<Product>
{
    // Add extra methods
}

public class ProductRepository : RepositoryBase<Product>, IProductRepository 
{
    // Implement extra methods
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...