2009/07/29

ActiveRecord Fluent Configuration

Earlier this morning I committed a first spike of code to the actual (post 2.0) trunk of ActiveRecord. This fluent configuration shows a lot of features I am planning for 2.x releases.

Let’s take a look at the new syntax. This one is for ActiveRecord itself and mere syntactic sugar:

    1 IActiveRecordConfiguration configuration = Configure.ActiveRecord

    2     .ForWeb()

    3     .Flush(DefaultFlushType.Leave)

    4     .UseThreadScopeInfo<SampleThreadScopeInfo>()

    5     .UseSessionFactoryHolder<SampleSessionFactoryHolder>()

    6     .MakeLazyByDefault()

    7     .VerifyModels()

    8     .RegisterSearch();

The following code is however more interesting. It does not only show how AR is currently configured, but also which features will become available soon:

    1 IStorageConfiguration configuration = Configure.Storage

    2     .For

    3         .AllOtherTypes()

    4         .MappedBy(new XmlNhibernateMapping()

    5             .InAssemblyOf<OneOfMyEntities>())

    6     .As

    7         .ConnectionStringName("a_string")

    8         .Driver<SqlClientDriver>()

    9         .ConnectionProvider<DriverConnectionProvider>()

   10         .Dialect<MsSql2005Dialect>()

   11         .ProxiedBy<ProxyFactoryFactory>()

   12         .ShowSql();

The first thing to note is the interface IStorageConfiguration. Each storage configuration will be used to create a NHibernate SessionFactory.

The storage configuration consists of two parts: The database configuration is syntactic sugar for the current NHibernate configuration strings, which are a pain in the neck especially if you need to declare types.

The more interesting part is the storage type selection. The part begins in line 2 by using the For-property. The storage type selection allows you to specify which types should use the session factory created by the storage configuration and how they are mapped.

The selection above contains all classes that are not explicitly added to another storage configuration (line 3) and it says that these types are mapped using classic NHibernate mapping files (line 4) which should be loaded from a given assembly (line 5).

Line 6 finally switches back to the storage configuration.

Storage Type Selections

The storage type selection shown above is effectively a specification pattern for types. Its existence shows to consequences for future versions of ActiveRecord:

  1. You can distribute your classes among multiple databases without the need of a common abstract baseclass. It will be possible to select the types for a storage by namespace, assembly, supertype, interfaces implemented or simply by enumerating them in the storage type selection.
  2. ActiveRecord attributes will be only one option to map persistent types. Types mapped by HBM files or Fluent NHibernate will become first class citizens of ActiveRecord.

The specification patternfor storage type selection allows more complex combinations than currently shown. Here is another example:

    1 IStorageConfiguration auditConfig = Configure.Storage

    2     .For

    3         .SubtypesOf<AuditType>()

    4         .InNamespaceOf<DefaultAuditorType>() // logical and

    5         .MappedBy(new FluentNHibernateMapping()

    6             .InAssemblyOf<MyMappingClass>())

    7     .And // Logical or - we start the next StorageTypeSelection

    8         .TypesInAssemblyOf<MessagingImpl>()

    9         // No MappedBy defaults to ActiveRecord attributes

   10     .As

   11         .DefaultsFor<MsSqlServer2000Configuration>()

   12         .ConnectionString("server=bla;...");

Multiple selections can be created by using the And-property (line 7). Since the storage configuration holds an arbitrary number of storage type selections, this allows for a logical-or-construct. It also allows mixing different mapping types. In the example the first selection is mapped with Fluent Nhibernate (lines 5-6) and the second one with ActiveRecord attributes (line 9).

It is also possible to narrow down type selections by adding multiple specifications to a single type selection (lines 3 and 4). This means that only types are selected that satisfy all specifications. In the example only types are selected that inherit from AuditType and are in the same namespace as DefaultAuditorType.

Storage Configuration

The storage configuration (where the database is configured) is not yet as clearly defined as the storage type selection.

But it will contain default values for most database systems, a templating mechanism and special subconfigurations for fluently defining behaviour needed only occasionally, such as NHibernate Search configurations.

Does this work yet?

No. I just implemented enough to compile and run some simple tests. The features shown above will go into AR 2.1 and AR 2.2.

This article is mainly a showcase for the planned functionality. Suggestions, critic and patches are always welcome.

2 comments:

Caleb said...

Hey, thanks for the good work.

Is there any documentation on how to use this yet?

Markus Zywitza said...

Please see the last two sentences. It is just a syntax proposal I'm trying to get feedback on.