locked
Dependency Injection/IoC, NHibernate and getting them to work together RRS feed

  • Question

  • I'm trying to get my head around DI/IoC, NHibernate and getting them to work nicely together for an application that i'm developing.  I'm quite new to both NHibernate and DI/IoC so not quite sure whether what i'm doing is the sensible way to be going about it. This is the scenario:

    The application provides users with the ability to calculate a particular value (known as the margin) for a particular financial transaction. The calculation of the marging value for each transaction is carried out by concrete implementations of an abstract MarginCalculator class and the concrete implementation to be used depends on the type of the product for the particular transaction (given by a certain field of the product object). The concrete calculator class is accessed via a property on the product class. i.e.

    public class Transaction
    {
        private double _margin;
        private Product _product;
        private Client _client;
       
        public double Margin { get; }
        public Product Product { get; }
        public Client Client { get; }
       
        public Transaction(Product p, Client c)
        {
            _product = p;
            _client = c;
        }
       
        public void CalculateMargin()
        {
            _margin = _product.MarginCalculator.CalculateMargin();
        }
    }

    public class Product
    {
        private string _id;
        private string _productType;
        ... Other fields
       
        public string Id { get; }
        public string ProductType { get; }
        public MarginCalculator MarginCalculator
        {
            get { return MarginCalculatorAssembler.Instance.CreateMarginCalculatorFor(this.ProductType); }
        }
    }

    public class MarginCalculatorAssembler
    {
        public static readonly MarginCalculatorAssembler Instance = new MarginCalculatorAssembler();

        private MarginCalculatorAssembler ()
        {
        }

        public MarginCalculator CreateMarginCalculatorFor(string productType)
        {
            switch (productType)
            {
                case "A":
                    return new ConcreteMarginCalculatorA();
                case "B":
                    return new ConcreteMarginCalculatorB();
                default:
                    throw new ArgumentException();
            }
        }
    }

    public abstract class MarginCalculator
    {
        public abstract double CalculateMargin();
    }

    public class ConcreteMarginCalculatorA : MarginCalculator
    {
        public override double CalculateMargin
        {
            // Perform actual calculation
        }
    }

    public class ConcreteMarginCalculatorB : MarginCalculator
    {
        public override double CalculateMargin
        {
            // Perform actual calculation
        }
    }

    Users select a particular client and Product from dropdowns and the corresponding clientId and productId are passed to repositories that then use NHibernate to populate product and client objects before they're injected into the transaction object. In my current setup the Transaction receives its Product and Client dependencies via constructor dependency injection (no IoC container used as yet) i.e.

    public class ProductRepository : IRepository<Product>
    {
        public Product GetById(string id)
        {
            using (ISession session = NHibernateHelper.OpenSession())
                return session.Get<Product>(id);
        }
    }

    /* Similar repository for Clients */

    IRepository<Client> clientRepository = new ClientRepository();
    IRepository<Product> productRepository = new ProductRepository();
    Client c = clientRepository.GetById(clientId);
    Product p = productRepository.GetById(productId);

    Transaction t = new Transaction(p, c);

    The following are what i'm hoping to get ideas on:

    a. Is it considered OK to be accessing the MarginCalculator (which is essentially a service) through the Product domain object or should, as suggested here, (http://stackoverflow.com/questions/340461/dependency-injection-with-nhibernate-objects) the code be restructured so as to remove service dependencies from the domain objects and instead create a new TransactionProcessor class that takes the abstract MarginCalculator as a dependency (along the lines of what's described here (http://www.lostechies.com/blogs/jimmy_bogard/archive/2008/03/31/ptom-the-dependency-inversion-principle.aspx)) i.e.

    public class TransactionProcessor
    {
            private readonly MarginCalculator _marginCalculator;
           
            public TransactionProcessor(MarginCalculator marginCalculator)
            {
                _marginCalculator = marginCalculator;
            }
           
            public double CalculateMargin(Transaction t)
            {
                return _marginCalculator.CalculateMargin(Transaction t);
            }
    }

    public abstract class MarginCalculator
    {
        public abstract double CalculateMargin(Transaction t);
    }

    b. Is it possible to use an IoC Container to get a Transaction object with NHibernate populated/generated Product and Client dependencies injected? i.e. Given a productId and clientId, both provided by the user, is it possible to have something like:

    // pseudocode
    Transaction t = IoC.Resolve<Transaction>(productId, cclientId);

    such that the container resolves the Product and Client dependencies of the Transaction object, NHibernate is utilised to populate the Product and Client based on the productId and clientId and then the populated Product and Client are injected into the Transaction?

    c. In a typical DI scenario, if class A has a dependency on interface B then the following might be done:

    IInterfaceB b = new ClassB();
    A a = new A(b);

    interface IInterfaceB
    {
    }

    class B : IInterfaceB
    {
    }

    public class A
    {
        private IIntefaceB _b;
       
        public A(IInterfaceB b)
        {
            _b = b;
        }
    }

    However, this, which is virtually how all examples of DI are shown, assumes that the implementor of IInterfaceB (in this case Class B) is known at design time. Is there a way to use DI in such a way that the implementor is determined at runtime?

    Many thanks

    Matthew
    Tuesday, December 23, 2008 12:25 AM

All replies

  • Well you are running into the realm of imperative vs declarative use DI/IoC.  If you were using a declarative DI/IoC like springframework or Unity then you can wireup your objects in XML file instead of imperatively writing in the code.  This is the case you would need if you want to use a concrete class that is not determined during the development time.  You could write a new concerete class way later something like even a year later after your application has been running in production...

     

    Tuesday, December 23, 2008 3:29 AM
  • Ad. a

    I agree that better desing would be to remove service instance from domain model class. It would make your domain model more reusable in different contexts. Service classes (like TransactionProcessor you've writter or the one I propose below) should be instantiated by the UI (using a DI container, of courseWink)

    Ad. b

    I would be a very difficult scenario I suppose, but I think it could be possible in some containers (using some extensions). But I think there is a reason (apart from technical difficulties) not to do this. It just hides your pretty well desing data access code (using repository pattern) and pretends that there is no data access here (just container-based resolution). I like explicit solutions.

    Another design could be to make Transaction itself a TransactionProcessor class. Than transaction should accept both repositories (and mentioned belowe MarginCalculatorFactory) in the constructor and the CalculateMargin method would have paramters for product id and customer id

    Ad. c

    I don't know if I correctly understood your question, but I think you should look at http://code.google.com/p/autofac/wiki/ComponentCreation, section Selection of an Implementer based on a Parameter Value. It lets your register in the container a mapping which leads to different implementation based on run-time provieded parameter value. Should solve the problem of creating proper instance of MarginCalculator.

    BTW, a factories topic (MarginCalculator is a canonical example of good place for a factory pattern) is a difficult one in context of DI containers. The most elegant design I think of would be to define MarginCalculatorFactory class with CreateCalculator method. But then you do not need a container any more, at least for dependencies. On the other hand, containers have usually some additional features (like aspect injection) which is quite useful in factories context. The question is how to force container to produce concrete implementations of objects on behalf of a factory.

    Best design I created so far is something like this:

    internal class CalculatorImpl1 : MarginCalculator {}
    internal class CalculatorImpl2 : MarginCalculator {}

    public class MarginCalculatorFactory
    {
    private readonly IContainer _factoryLevelContainer;

    public MarginCalculatorFactory(IContainer mainContainer)
    {
    _factoryLevelContainer = mainContainer.CreateChildContainer()
    _factoryLevelContainer.RegisterType<MarginCalculator, CalculatorImpl1>("product1");
    _factoryLevelContainer.RegisterType<MarginCalculator, CalculatorImpl2>("product2");
    }
    public MarginCalculator CreareCalculator(string productType)
    {
    return _factoryLevelContainer.Resolve<MarginCalculator>(productType);
    }
    }

    Hope that will help you
    Tuesday, December 23, 2008 6:31 AM
  • Szymon,

    Thanks for you reply.

    A: I think i agree with you and are leaning more towards removing the service class from the domain obect - Does anyone else have any other/further thoughts on which approach would be better in terms of bests practices (loose coupling ,testing etc...)?

    B: I've cross-posted over at stackoverflow (http://stackoverflow.com/questions/387783) and the first answer suggests that existing IoC frameworks (one of them at least, LinFu) are capable of injecting prepopulated dependecies. However, if i've understood correctly it is, as you suggest, by means of extension of vanilla DI/IoC concepts.

    More importantly, i think your question as to whether this should be done in the first place as it uses the container to hide/encapsulate the data access, is interesting. What do others think? Is the use of an IoC/DI container to resolve and inject dependencies that have been pre-populated using a presistence framework (ORM) a good practice?

    C: Is the MarginCalculatorFactory that you are proposing an example of selecting an implementer based on parameter value? Do you know which of the other major DI/IoC frameworks also support this and what in their own terminology, they call it? (i know what i want to do but i don't know what the correct terminology for it is so i don't know what to look for in the frameworks documentations) Smile

    Thanks

    Matthew
    Tuesday, December 23, 2008 9:34 AM