2009/08/01

ActiveRecord 2.0

Finally it’s final. I just created the ActiveRecord 2.0 zipfile.

It can be downloaded at SourceForge. This release includes the NHLinq 1.0 release.

Have Fun!

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.

2009/07/21

ActiveRecord Release Candidate

 

RC 1 of ActiveRecord 2.0 is now available on SourceForge.

Unless serious bugs are found within, this version will be released as ActiveRecord 2.0 RTM on August, 1st.

2009/07/14

German Blog reactivated

 

My german blog is here.

ActiveRecord Beta 1 released

 

The first beta of ActiveRecord 2.0 has been released last weekend. You can get it from Sourceforge.

Changes

Beta 1 took about two months to complete, mostly due to the number of last minute additions to the 2.0 release. The highlights are:

In-Memory-Testing

It’s now possible to test your schema without hitting a database. Inherit from our base class to specify your favorite framework’s infrastructure and the classes/assemblies to test:

    1 public class TestBase : InMemoryTest

    2 {

    3     public override Type[] GetTypes()

    4     {

    5         return new [] {typeof(Blog), typeof(Post)};

    6     }

    7 

    8     [SetUp]

    9     public override void SetUp()

   10     {

   11         base.SetUp();

   12     }

   13 

   14     [TearDown]

   15     public override void TearDown()

   16     {

   17         base.TearDown();

   18     }

   19 

   20     public override IDictionary<string, string> GetProperties()

   21     {

   22         return new Dictionary<string, string>() { {"show_sql", "true"} };

   23     }

   24 }

You can then simply create tests that don’t need a database:

    1 [TestFixture]

    2 public class CRUDTests : TestBase

    3 {

    4     [Test]

    5     public void Create()

    6     {

    7         var blog = new Blog { Name = "Blog" };

    8         blog.Save();

    9 

   10         var post = new Post { Title = "Post", Blog = blog };

   11         blog.Posts.Add(post);

   12 

   13         blog.Save();

   14     }

   15 }

Note: The tests shown above have no app.config altogether!

Basic LINQ Support

The formerly contrib project Castle.ActiveRecord.Linq has been added to ActiveRecord.

Please note that the underlying NHLinq implementation is not fully implemented. Some features are still missing, i. e. joins between unrelated entities.

NHSearch integration

If you want to search your entities, NHSearch is the right project for you. The current release simplifies usage within ActiveRecord by registering the listeners for you when you add searchable=”true” to your ActiveRecord-configuration.

More on using NHSearch can be found on this wiki page

2009/06/05

Understand ActiveRecord mapping: Collections of simple objects

Recently I had a post in the Castle user’s group about mapping a collection of enums with ActiveRecord. Since I know it’s just as mapping other simple types, I only referred to the documentation of the Element and ElementType properties of the HasMany attribute.

But, it turned out it is not really clear to many how to map a collection of simple values using HasMany. Therefore I decided to prepare an explanatory post, which is what you are reading now.

Mapping Basics

The problem: I want to hold a collection of enum values, say I have a status enum and want a history of that status persisted. Here is my model:

namespace EnumMapping
{
	[ActiveRecord]
	public class Article
	{
		[PrimaryKey]
		public virtual int Id { get; set; }

		[Property]
		public virtual string Author { get; set; }

		[Property]
		public virtual string Title { get; set; }

		[Property]
		public virtual Status CurrentStatus { get;set;}

		[HasMany(...)]
		public virtual IList StatusHistory
		{
			get { return statusHistory; }
			set { statusHistory = value; }
		}
		private IList statusHistory = new List();

	}

	public enum Status
	{
		None, Planned, InWriting, InEditing, Released 
	}
}

The ellipsis in the HasMany attribute is by design. I will work out in this post what you have to put here, so I let it out to make you understand the post, and not just read the code and copy and paste it.

To understand what information ActiveRecord requires to map this collection, we first will take a look into how these collections are saved in the database:

image

As expected, we have to tables. The Article table stores all the simple properties, but it cannot store collections. In a relational model, collections are always modeled by foreign key relations. That means we need a second table that stores both the values and the link to the article in question.

Note: You might have noticed that the StatusHistory table does not have a primary key. This is because of the bag semantics we currently have for this collection. More efficient semantics are shown later.

Looking at the StatusHistory table again, we see what we have to tell ActiveRecord to fetch the values for us and populate our List:

What is the table’s name?

 image

We take that name and put it into the respective property of the HasMany attribute:

[HasMany(Table="StatusHistory",
	...)]
public virtual IList StatusHistory {...}

As you can see from the code, we are not through yet.

Which column refers to the article?

image

[HasMany(Table = "StatusHistory",
	ColumnKey = "article",
	...)]
public virtual IList StatusHistory {...}
Which column holds the value?

image

[HasMany(Table = "StatusHistory",
	ColumnKey = "article",
	Element = "status",
	...)]
public virtual IList StatusHistory {...}

What? There is even more to specify even though we already have all columns included?

Yes. ActiveRecord also needs to know the types of the columns. The foreign key’s column can be inferred from the types primary key, but we need to know what type the value actually has.

[HasMany(Table = "StatusHistory",
	ColumnKey = "article",
	Element = "status",
	ElementType = typeof(Status))]
public virtual IList StatusHistory {...}

That’s it (for now). We now can take that mapping and go for the database.

The Collection Types

I already mentioned the missing primary key on the collection’s table and that the collection uses bag semantics. So what are these semantics? There are a few available in ActiveRecord:

  • Bag: All elements are unordered and may appear multiple. Total chaos.
  • Set: The elements are unordered, but each one can be present only once. This is the typical relational collection.
  • List: Elements are ordered and may be there multiple times.
  • Dictionary: Elements have a key that identifies them.

If the collection type is not specified, ActiveRecord assumes that you want bag semantics. After all, that’s what a collection is. Put things in there and get them out. No one cares for ordering or duplication.

Unfortunately, this is quite inefficient with databases:Items in a bag cannot be updated individually. Recall that there is no primary key in the collection table. Since the value can be in the collection more than once, an update or delete would effect all rows with that value. As a result, every time the collection is updated, it is completely deleted from the DB and inserted again.

To get around this, we could use a set. However, this requires us to use another Collection type, Set<Status> from Iesi.Collections. So instead of a set, I will use a list semantic. This is suitable, because a status history has an implicit ordering.

To use the list semantic, the schema must be changed first, because an index column is needed to store the list’s index.

image

We now don’t have only an additional column, we also have a nice primary key consisting of the combination of the article’s id and the list’s index. So every value in the list can now be updated individually.

Now we must tell ActiveRecord to use list semantics and how to find the index:

[HasMany(Table = "StatusHistory",
	ColumnKey = "article",
	Element = "status",
	ElementType = typeof(Status),
	RelationType = RelationType.List,
	Index = "idx")]
public virtual IList StatusHistory {...}

That’s it.

2009/05/08

ActiveRecord Alpha Release

 

You will have already heard it: It is release season in the Castle’s domain.

The newest release is ActiveRecord 2.0 Alpha 1, recently uploaded to http://groups.google.com/group/castle-project-users/web/ActiveRecord2.0Alpha1.zip

This release includes a lot of breaking changes with regard to the last release, ActiveRecord 1.0 RC3, which is the main reason for going through a new complete release cycle starting with alpha releases.

This release includes a move from NHibernate 1.2 to NHibernate 2.1. Please make sure to read the Changes.txt and start testing early.

Bugs can be posted at donjon and last-minute-features can be suggested at UserVoice.

There is no feature freeze yet: All suggestions on UserVoice that get 15+ votes there until May 17th, will be considered for addition in Alpha 2. If no features take this hurdle, I will move forward to Beta 1.