NHibernate 与控制反转

发布于 2024-09-18 12:18:55 字数 620 浏览 3 评论 0原文

这只是我一直在思考的事情,想知道它是否存在,或者是否有好处。

我正在使用 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);
    }
}

我认为传递“ICustomer”并以某种方式配置 nHibernate 来执行 IoC 会很酷,而不是将“Customer”作为类型参数传递给会话。这可能吗,或者有什么好处吗?

This is just something I've been thinking about and was wondering if it exists, or even if its beneficial at all.

I'm doing inversion of control and dependency injection using Unity. I'm also doing ORM with fluent nHibernate. I was wondering if there was a way to either configure nHibernate to take interfaces as its type parameters and do IoC for me, or what the best way to use them together would be.

For instance, if I had a customer object using a repository pattern I would possibly have 2 interfaces (ICustomer, ICustomerRepository) as well as 2 concrete implementations (Customer, CustomerRepository). In the concrete CustomerRepository I would have to tie it directly to the Customer object in order to use nHIbernate.

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

Instead of passing "Customer" as a type parameter to the session, I think it would be cool to pass "ICustomer" and somehow have nHibernate configured to do the IoC. Is this even possible, or beneficial at all?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

呆萌少年 2024-09-25 12:18:56

当我们开始设计应用程序时,我有完全相同的想法。然而,很快我们就遇到了仅使用基于接口的类型的一些问题,因此我们通过使用具体类型和松散存储库(即 Customer 和 ICustomerRepository)进行妥协。

我试图回忆我们遇到了什么问题,但现在我一片空白。

When we started designing our application, I had the exact same idea. However, pretty soon we ran into some issues with using only interface based types, so we compromised, by using concrete types and loose repositories, meaning Customer and ICustomerRepository.

I'm trying to recall what issues we ran into, but right now I'm blanked out.

锦爱 2024-09-25 12:18:56

ICustomer 放入 NHibernate 中并没有真正的优势。 NHibernate 本身应该只是一个带有几个钩子的黑盒子,您可以将模拟附加到其中。你可以模拟 NHibernate 中的实现;它并不真正关心里面使用了什么对象。

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


哦,顺便说一句,当你的存储库已经是一个额外的 IoC 容器时,为什么还要使用 NHibernate 作为额外的 IoC 容器呢?

There is no real advantage in throwing in an ICustomer into NHibernate. NHibernate itself should just be a black box with a couple of hooks where you can attach your mocks to. As you can mock the implementation in NHibernate; it doesn't really care what objects are used inside.

When mocking this method, you can do all of this with the ISession and IQuery from NHibernate, and the ICustomerRepository from your own code. No need to add an extra abstraction.


Oh, and btw, why have NHibernate as an additional IoC container when your repository already is?

挽手叙旧 2024-09-25 12:18:56

将 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 中。

One way to integrate your IOC container (Unity) with NHibernate, is to use Unity to resolve the type you'll pass to NHibernate.

This accomplishes what I think is your aim, which is to have in only one place the mapping between interface and implementation.

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);
    }
}

Obviously, you can't use NHibernate's generic overloads, but I think they all have non-generic equivalents.

The one other place in which you'll have to reference the concrete implementation is in your FNH ClassMap<T>s.

白首有我共你 2024-09-25 12:18:56

我看不到这样做有任何很大的灵活性,但为了实现你所要求的,你可以尝试:

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

}

I can't see any great flexibility from doing this but to achieve what you're asking you could try:

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

}
下雨或天晴 2024-09-25 12:18:56

使用 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。

我希望你能明白我的想法。

An example of using IOC would be to find the concrete implementation of ICustomerRepository

// in your client code.

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

// a framework of the 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>();
        }
}

In the example above, I am using Castle Windsor as my IOC. Please adapt your implementation to use Unity Block.

I hope you'd get my idea across.

羁绊已千年 2024-09-25 12:18:56

如果您打算有一个 ICustomer 接口,这是否表明您想用其他东西代替 Customer?会是这样吗?如果是的话那么用什么?

您的客户类应该是您的域的一部分,以及其他实体(例如产品、订单等)。您的域应该构成整个应用程序的中心部分。我认为您应该努力使域实体与 NHibernate 数据访问代码解耦,这似乎是通过存储库接口实现的。

如果您想创建具有特定 Customer 实现的基本 Customer,那么请使用继承,Nhibernate 对此支持非常好:NHibernate

public abstract class Customer { }

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

足够强大,可以在您调用 return _session.Get(id);< 时实例化正确的类型。 /code> 无需自己显式转换。

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

If you're going to have an ICustomer interface, this would suggest you want to substitute Customer for something else? Would this be the case? If so then with what?

Your Customer class should be part of your domain, along with other entities such as Product, Order etc etc. Your domain should form the central part of your entire application. I think your efforts should move toward keeping your domain entities decoupled from your NHibernate data access code, which you seem to be achieving with Repository interfaces.

If you want to create a base Customer with specific Customer implementations, then use inheritance, which Nhibernate supports really well:

public abstract class Customer { }

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

NHibernate is powerful enough to instantiate the correct type when you call return _session.Get<Customer>(id); without having to explicitly cast it yourself.

Perhaps this is what you're after. Have a look at the NHibernate documentation on inheritance: http://nhibernate.info/doc/nh/en/index.html#inheritance

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文