How to inject ORM with some IoC?
This post continues ORM+IoC series, namely - the discussion initiated by “How to decouple your code from ORM (XPO) while granting it the power to IoC?” and comments that followed.
Let us try to inject ORM itself with some IoC and see what happens. Take a look at the following exaggerated command example:
public sealed class CreateRandomAccount : ICommand
{
private readonly Account _account;
private readonly ILog _log;
public CreateRandomAccount(Account account, ILog log)
{
_account = account;
_log = log;
}
public void Execute()
{
_log.Write("Creating new random account");
_account.Name = Guid.NewGuid().ToString();
_account.Disabled = true;
_account.Save();
}
}
I like to use some ICommand implementations as examples since they help to crystallize the effects of IoC in one single piece.
The code above, being resolved in some container, just does what it says: it asks for the class (registered as Factory instance) and saves it to some repository. IoC uses Session from the current scope to create the instance and so it will use UoW, session in transaction or whatever session descendant is available in the container. Additionally it writes a note to the logger.
These are the required bits to achieve this:
var builder = new ContainerBuilder();
// register log
builder.Register<ConsoleLog>().As<ILog>();
// register command with name
builder.RegisterCommand<CreateRandomAccount>("CreateRandom");
// register all ORM objects
builder.RegisterTypesAssignableTo<XPBaseObject>().FactoryScoped();
// register the session with the default connection
builder.Register(c => new Session()).ContainerScoped();
using (var build = builder.Build())
{
// execute some command
build.Resolve<ICommand>("CreateRandom").Execute();
}
Now, without modifying the command logic (imagine that it is located in some 3rd party business component assembly) let’s make sure that we track every change to any Account object. We add ConsoleChangeTracker (just one-line implementation that writes change events to the console) and replace the registration logic from “RegisterTypesAssignableTo” to lambda registration:
builder.Register<ConsoleChangeTracker>() .As<IChangeTracker>(); builder.Register(c => Track(new Account(c.Resolve<Session>()), c)) .FactoryScoped();
“Track” is simply a method group with the following code:
private static T Track<T>(T item, IContext c) where T : XPBaseObject
{
var tracker = c.Resolve<IChangeTracker>();
item.Changed += tracker.Track;
return item;
}
When we run this thing we get the following console output:

Ok, that looks easy, since we control the object creation. But what about working with the objects that are loaded by the ORM? The implementation logic should not know about it and it should use some simple interface like this one:
public interface IRepository<T> : IList<T>
{
string CriteriaString { get; set;}
}
So, let’s use it:
public sealed class DisableAllAccounts : ICommand
{
private readonly IRepository<Account> _accounts;
private readonly ILog _log;
public DisableAllAccounts(IRepository<Account> accounts, ILog log)
{
_accounts = accounts;
_log = log;
}
public void Execute()
{
_log.Write("Disabling accounts:");
_accounts.CriteriaString = "Disabled=0";
foreach (var account in _accounts)
{
_log.Write(account.Name);
account.Disabled = true;
account.Save();
}
}
}
In order to pull that trick we keep the account tracker setup, but add a few more container registrations, replacing the old Session with our own implementation:
builder.RegisterGeneric(typeof (FireCollection<>)) .As(typeof (IRepository<>)) .ContainerScoped(); builder. Register<Session>(c => new FireSession(type => c.Resolve(type))) .ContainerScoped(); builder.Register<Session>(c => new FireSession(type => c.Resolve(type))) .ContainerScoped();
But what is “FireSession”?
FireSession simply inherits from Session by XPO and adds resolver lambda to its constructor signature (the one we pass to it in the registration). Then, while creating any new object it (ObjectLoader, actually) uses the container resolution instead of the XPClassInfo creation routine, so that any created object gets normal dependency injection. FireCollection is just a XPCollection wrapper. So, when we run the modified code, we get:
Notes:
- All repositories and business objects with scope/factory initiation will be automatically disposed as soon as the scope goes out of the range
- If multiple instances depend on some scoped object, then they will share it. For example, all commands running in the same scope will share Session and Repository instances (these are created with first request).
- Do not try to pull this trick at home unless your IoC supports scopes and lambda resolution (like autofac does) and ORM has features similar to eXpress Persistent Objects.
- The code is not absolutely decoupled from the ORM. In this sample we still use Account object that inherits from the XPObject (XPO requirement). Adding interface-level abstraction here is possible (only IoC will know about the implementation class) but would require some additional code.
ORM+IoC series will be continued with the topic: How to use ORM (XPO), IoC, C# 3.5 syntax, Linq and .NET 2.0 together?
PS: You might also want to check curious discussion on reusable domain models in the DevExpress blog. And there is always the list of current articles on xLim approach.
PPS: I’ll try to outline the primary issues with the eXpress Application Framework (read “ways how it could be improved”) in one of my next posts.
8 Comments to How to inject ORM with some IoC?
We’re definitely getting there, but I’m still not quite sure my point is being seen yet. :)
Your example, however, provides what I hope will be a perfect entry point into what I’ve been trying to get at:
Presumably Account.Save() talks directly to the ORM. If so, how can you unit test each of these example commands?
Jeremy,
I knew that you would ask - see the last bullet-note in this article))
Simple brute-force solution is:
1) pull everything to the IAccount interface (including Save method, repeat for other BOs…)
2) register Account as IAccount and keep the existing Account registration as type (session will need it since it has to do some low-level work).
3) wrap the enumerator of the FireCollection with interface explicit implementation that returns IAccount (and do that for any other members that you need to use).
Then, you could ask IoC for IRepository{IAccount} or use IAccount to create new instances.
But I neither like this approach nor advice it - the objects will have to travel back from IAccount to Account inside the actual implementation, and that just does not feel right.
That’s why I haven’t mentioned this approach in the primary post.
Rinat
March 7, 2008
The problem with the approach you like is that it can’t be unit-tested. The (admitted) problem with the approach you do not like is that (as many others have pointed out over the years) serviced entities just “feel” weird, and can definitely add overhead depending on injection techniques used. I do admit that I am still searching for a way to both have good DDD (which means zero anemic domain model anti-pattern effects) and good abstraction (primarily for testability, but also for more subjective general design quality improvements) at the same time.
Every time the subject comes up across the blogosphere, however, it becomes pretty clear that people are choosing _between_ the two. They are either having good DDD, but are more tightly coupled, less abstracted, and have testing issues, or they are having good loose coupling, beter abstractions, and better testing, but are doing so at the cost of heading towards anemic domain models and Fowler-esque “transaction script”-style services.
Perhaps one of these days we’ll have both. I’m going to try to force this to happen on my next pet project just to see how things go. If I come up with anything interesting, I’ll be sure to mention it. :) In the meantime, I’ll be continuing my already-years-long search for a solution.
Jeremy,
I didn’t say that I like this approach to much to move it into the xLim 2 body of knowledge)) The bit feels nice and promising, but there has to be more to it.
One of the probable solutions to the problem is to integrate IoC and DDD together. This bit will be quite complex and resource-consuming (multiply ORM by IoC) but if it has the proper dev team with experience in both worlds then it could live with that.
DevExpress folks are trying to achieve that by implementing their reusable domain models. But this looks too heavy for me.
There should be some other simple and logically beautiful solution, but we just do not see it yet…
Good luck with your search and, please, do not hesitate to share your findings))
Best regards,
Rinat Abdullin
March 7, 2008
Will do, and thanks for all the great posts. I’ll definitely be keeping an eager eye on your blog to see how you do with XPO et al over time!
Jeremy,
It was fun while the riddle lasted, but I think I’ve got the solution.
And I like it))
I’ll write the proper post tomorrow after another one that I’ve delayed for too long..
March 7, 2008
Hehe. Nice to see that I’m not the only one that has had this issue gnawing at me for ages. :)
March 8, 2008
[...] us get back to the IoC+ORM series and take one more look at the ICommand implementation from the last post. It could be improved quite a [...]
Leave a comment
Search
Archives
Recent Comments
- aCoder on Extension methods for interfaces
- Requirements for the Photon .NET project | Rinat Abdullin on IRepository, cross-cutting concerns and flexibility
- Nicholas Blumhardt on Extension methods for interfaces
- aCoder on IRepository, cross-cutting concerns and flexibility
- Rinat Abdullin on Blog upgraded
- Rinat Abdullin on Extension methods for interfaces
- IRepository, cross-cutting concerns and flexibility | Rinat Abdullin on Extension methods for interfaces
- Bill Pierce on Blog upgraded
- aCoder on Extension methods for interfaces


March 6, 2008