NHibernate с инверсией управления - PullRequest
2 голосов
/ 13 сентября 2010

Это просто то, о чем я думал и задавался вопросом, существует ли оно, или даже если оно вообще полезно.

Я делаю инверсию управления и внедрение зависимостей, используя Unity.Я также делаю ORM с беглым nHibernate.Мне было интересно, есть ли способ либо сконфигурировать nHibernate, чтобы брать интерфейсы в качестве параметров его типа и делать IoC для меня, либо каков наилучший способ их использования вместе.

Например, если бы у меня былобъект customer, использующий шаблон репозитория, возможно, у меня будет 2 интерфейса (ICustomer, ICustomerRepository), а также 2 конкретные реализации (Customer, CustomerRepository).В конкретном CustomerRepository мне пришлось бы привязать его непосредственно к объекту Customer, чтобы использовать nHIbernate.

public class CustomerRepository : ICustomerRepository
{
    public ICustomer Retrieve(int id)
    {
        return _session.Get<Customer>(id);
    }
}

Вместо передачи «Customer» в качестве параметра типа для сеанса, я думаю, что это было бы здоровочтобы пропустить "ICustomer" и каким-то образом настроить niber на ioC.Это вообще возможно или вообще выгодно?

Ответы [ 6 ]

1 голос
/ 13 сентября 2010

Один из способов интеграции вашего контейнера IOC (Unity) с NHibernate - это использование Unity для определения типа, который вы передадите NHibernate.

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

public CustomerRepository : ICustomerRepository
{
    Type customerType;

    // ISession[Factory] injection omitted for brevity

    public CustomerRepository(IUnityContainer container)
    {
        registration = container.Registrations.FirstOrDefault(
            x => x.RegisteredType.Equals(ICustomer));

        if(registration == null) 
        {
            throw new ApplicationException(
                "No ICustomer implementation was registered.");
        }

        customerType = registration.MappedToType;
    }

    public ICustomer Retrieve(int id)
    {
        return _session.Get(customerType, id);
    }
}

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

Еще одно место, в котором вам придется ссылаться на конкретную реализацию, - это ваши FNH ClassMap<T> s.

1 голос
/ 13 сентября 2010

Нет реального преимущества в добавлении ICustomer в NHibernate.Сам NHibernate должен быть просто черным ящиком с парой крючков, к которым вы можете прикрепить свои макеты.Как вы можете посмеяться над реализацией в NHibernate;на самом деле все равно, какие объекты используются внутри.

При издевательстве над этим методом вы можете делать все это с ISession и IQuery из NHibernate и ICustomerRepository из вашего собственного кода,Не нужно добавлять дополнительную абстракцию.


Да, и кстати, почему NHibernate является дополнительным контейнером IoC, когда ваш репозиторий уже есть?

1 голос
/ 13 сентября 2010

Когда мы начали разрабатывать наше приложение, у меня была точно такая же идея.Однако довольно скоро мы столкнулись с некоторыми проблемами с использованием только интерфейсных типов, поэтому мы пошли на компромисс, используя конкретные типы и свободные репозитории, то есть Customer и ICustomerRepository.

Я пытаюсь вспомнить, с какими проблемами мы столкнулись, но сейчас я отключен.

1 голос
/ 13 сентября 2010

Я не вижу большой гибкости от этого, но для достижения того, что вы просите, вы можете попробовать:

public abstract class AbstractCustomerRepository<T> : ICustomerRepository where T : class, ICustomer
{
    public ICustomer Retrieve(int id)
    {
        return _session.Get<T>(id);
    }
}

public class CustomerRepository : AbstractCustomerRepository<Customer>
{

}
0 голосов
/ 14 сентября 2010

Пример использования IOC - найти конкретную реализацию ICustomerRepository

// в коде вашего клиента.

ICustomerRepository dao = ServiceFactory.GetServiceInstance<ICustomerRepository>();

// фреймворк ServiceFactory

public static class ServiceFactory
{
        private WindsorContainer m_container;

        public static T GetServiceInstance<T>()
        {
              // use your IOC to resolve your <T>
               return m_container.Resolve<T>();
        }
}

В приведенном выше примере я использую Castle Windsor в качестве МОК. Пожалуйста, адаптируйте вашу реализацию для использования Unity Block.

Я надеюсь, что вы поняли мою идею.

0 голосов
/ 13 сентября 2010

Если у вас будет интерфейс ICustomer, это может означать, что вы хотите заменить Customer другим?Будет ли это так?Если да, то чем?

Ваш класс Customer должен быть частью вашего домена, наряду с другими объектами, такими как Product, Order и т. Д. И т. Д. Ваш домен должен составлять центральную часть всего вашего приложения.Я думаю, что ваши усилия должны быть направлены на то, чтобы ваши доменные объекты были отделены от кода доступа к данным NHibernate, чего вы, похоже, добиваетесь с помощью интерфейсов репозитория.

Если вы хотите создать базового клиента с конкретными реализациями клиентов, то используйтенаследование, которое действительно хорошо поддерживает Nhibernate:

public abstract class Customer { }

public class EnterpriseCustomer : Customer { }
public class SmbCustomer : Customer { }
public class IndividualCustomer : Customer { }

NHibernate достаточно мощен, чтобы создавать экземпляр правильного типа при вызове return _session.Get<Customer>(id); без необходимости явного приведения его самостоятельно.

Возможно, это то, чтоты после.Взгляните на документацию NHibernate по наследованию: http://nhibernate.info/doc/nh/en/index.html#inheritance

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...