NHibernate与控制反转

时间:2010-09-13 13:07:11

标签: c# .net nhibernate fluent-nhibernate

这只是我一直在考虑的问题,并且想知道它是否存在,或者它是否有益。

我正在使用Unity进行控制和依赖注入的反转。我也用流利的nHibernate做ORM。我想知道是否有办法将nHibernate配置为接口作为其类型参数,并为我做IoC,或者将它们组合在一起的最佳方式是什么。

例如,如果我有一个使用存储库模式的客户对象,我可能会有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”并以某种方式将nHibernate配置为执行IoC会很酷。这甚至是可能的,还是有益的?

6 个答案:

答案 0 :(得分:1)

我无法看到这样做的任何灵活性,但要实现你所要求的,你可以尝试:

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>
{

}

答案 1 :(得分:1)

当我们开始设计我们的应用程序时,我有完全相同的想法。但是,很快我们就遇到了一些仅使用基于接口的类型的问题,所以我们通过使用具体类型和松散的存储库来妥协,这意味着Customer和ICustomerRepository。

我想回忆一下我们遇到的问题,但现在我已经被淘汰了。

答案 2 :(得分:1)

向NHibernate投掷ICustomer没有什么好处。 NHibernate本身应该只是一个带有几个挂钩的黑匣子,你可以把你的嘲笑附加到。你可以在NHibernate中模拟实现;它并不关心里面使用的是什么对象。

在模拟此方法时,您可以使用NHibernate中的ISessionIQuery以及您自己代码中的ICustomerRepository来完成所有这些操作。无需添加额外的抽象。


哦,顺便问一下,为什么当您的存储库已经存在时,NHibernate会作为额外的IoC容器?

答案 3 :(得分:1)

将您的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>

答案 4 :(得分:0)

如果您要使用ICustomer界面,这会建议您替换客户其他内容吗?会是这种情况吗?如果是这样的话呢?

您的客户类应该是您的域的一部分,以及产品,订单等其他实体。您的域应该构成整个应用程序的核心部分。我认为您的努力应该转向保持您的域实体与您的NHibernate数据访问代码分离,而您似乎是通过Repository接口实现的。

如果你想创建一个具有特定Customer实现的基础Customer,那么使用Nhibernate非常支持的继承:

public abstract class Customer { }

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

当你调用return _session.Get<Customer>(id);时,NHibernate足以实例化正确的类型而无需自己明确地投射它。

也许这就是你所追求的。看看有关继承的NHibernate文档:http://nhibernate.info/doc/nh/en/index.html#inheritance

答案 5 :(得分:0)

使用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作为我的IOC。请调整您的实现以使用Unity Block。

我希望你能理解我的想法。