views:

104

answers:

6

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?

+1  A: 

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

}
wal
Jay
scroll across, where T : class, ICustomer
wal
@wal This isn't the same and won't even compile, in fact. If `ICustomerRepository` declares that the `Retrieve` method returns `ICustomer` its implementors must declare `ICustomer` as the return value.
Jay
duly noted and accepted. thanks.
wal
A: 

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.

jishi
+1  A: 

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?

Jan Jongboom
A: 

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://nhforge.org/doc/nh/en/index.html#inheritance

Sunday Ironfoot
I totally agree with what you're saying, but I think this only applies in a POCO type setting. If you're using Entities without POCO, then your business objects will be tied specifically to your ORM, which leaves the need to Interface them as well as your repositories. Because non POCO Entities objects would be littered with extra code that an nHibernate object wouldn't have.
Chris
+1  A: 

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.

Jay
This is actually a really cool idea! I didn't even think of doing it that way, thanks Jay!
Chris
A: 

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.

Syd
Hey Syd, I actually am using a pattern similar to this to get concrete implementations of my repositories. I was just thinking in terms of using my concrete repositories with nHibernate to have interfaces mapped to concrete implementations so I could pass an nHibernate session an interface and have it automatically resolve the dependency for me.
Chris