How to use ORM (XPO), IoC, C# 3.5 syntax, Linq and .NET 2.0 together?

One of the most important features of any proper development architecture, environment or process, is that the synergy (network) effects accumulate, if you keep doing the right things. IoC/DI, unit testing and TDD, continuous integration - all these just form up the external side of how everything works. They simply help (or force) to shape the logics of the development to make everything fold smoothly and let your solutions accumulate the benefits.

Now, let 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 bit:

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

Things become better as we throw out things that do not fit well. So let us remove our custom IRepository<> from this picture (along with the FireCollection behind it) and get rid of the string literal in favor of something that is compiler-checked

public sealed class DisableAllAccounts : ICommand
{
  private readonly IOrderedQueryable<Account> _accounts;
  private readonly ILog _log;

  public DisableAllAccounts(IOrderedQueryable<Account> accounts, ILog log)
  {
    _accounts = accounts;
    _log = log;
  }

  public void Execute()
  {
    _log.Write("Disabling accounts:");

    var accounts = from c in _accounts
      where (c.Disabled == false)
      select c;

    foreach (var account in accounts)
    {
      _log.Write(account.Name);
      account.Disabled = true;
      account.Save();
    }
  }
}

The new builder registration shows us that we rely on Linq for eXpress Persistent Objects support in this situation:

builder.RegisterGeneric(typeof (XPQuery<>)).
  As(typeof (IOrderedQueryable<>)).ContainerScoped();

Here we have another side (network) effect of throwing away some bits from the main code - we are no no longer coupled with the XPO criteria syntax. And we can feed this class with any other IOrderedQueryable implementation - it would not notice the difference (for the re-usability reasons it is advised to use the least possible interface in similar situations).

Additionally, it is possible to compile all the mentioned code to target .NET 2.0 (as all the code from my code snippets compiles into). However, in this case I was not able to use the LinqBridge library since it does not have support for the System.Linq namespace. But replacing LinqBridge with local System.Core and manually removing that RequiredVersion XmlNode from project references did make the compiler happy. More than that - code did execute without any problems inside virtual machine with just .NET 2.0 installed.

Now, if only we could get rid of that ORM object and use only its interface (while keeping the ORM with the ability to work with the actual object without any type casting)… you can check out the next post for this.

PS: R# 4.0 has just got first Linq syntax support these days so this piece plays here as well.

PPS: Synergy effects do not accumulate just from the good things. Ceteris paribus, any fixed force in a complex system that constantly pushes in specified direction, makes its effects accumulate in geometrical progression. Le Bon Gustave in his “La psychologie des foules” talks about similar tendencies in the sociological systems, while Alexander Bogdanov in “Tektology: Universal Organization Science” applied these principles to any system.

Simply put: constant denial of efficient development principles in a project leads to problems that stack up and slow the development till it is too expensive to go on.

Leave a Reply