Learning in the Open: II – first relation and more ActiveRecord

It took a little longer than I planned but here we go again. In the meantime ActiveRecord 2.1 was released, and soon after that a minor update bringing one cool big feature. From now on we’ll be working on version 2.1.2. Picking up from where we left off last time. We have a user entity. Since we’re building a website where users can publish benchmark results, we’ll create now a benchmark entity, and create a relation between these two.

I want to see results!

Let’s start by adding an appropriate field to the User class:

private readonly ICollection<BenchmarkResult> benchmarkResults = new HashSet<BenchmarkResult>();

We also create a property:

public IEnumerable<BenchmarkResult> BenchmarkResults

{

    get

    {

        foreach (var result in benchmarkResults)

        {

            yield return result;

        }

    }

}

So far this is just a regular property. To map it as a one-to-many relation we use the HasManyAttribute.

[HasMany(Access = PropertyAccess.FieldCamelcase, 

    Cascade = ManyRelationCascadeEnum.SaveUpdate, 

    RelationType = RelationType.Set,

    Inverse = true)]

public IEnumerable<BenchmarkResult> BenchmarkResults

There’s quite a lot going on here, so let’s go over it piece by piece

  • Access property FieldCamelcase specify we want ActiveRecord (and NHibernate underneath it) to go to the field directly, which makes sense since we’re exposing it as mere enumerable.
  • Cascade specifies that when saving or updating our user, all new and changed benchmark results in the collection should also be appropriately saved or updated.
  • Usually we wouldn’t have to specify type of the relation. Usually it will infer it from the kind of collection we expose, and would use set for ISet, map for IDictionary, bag for ICollection etc. However since we’re exposing only IEnumerable it does not have enough information to decide, that’s why we have to be explicit here.
  • We also specify Inverse property to be true, which basically means that it’s child’s task to maintain the relationship. That also means that child needs to have a reference to the parent.

Let’s now build our BenchmarkResult class.

[ActiveRecord]

public class BenchmarkResult : ActiveRecordLinqBase<BenchmarkResult>

{

    protected BenchmarkResult()

    {

    }

 

    public BenchmarkResult(User user, string benmchmarkName, string computerModel, double score)

    {

        if (user == null)

        {

            throw new ArgumentNullException("user");

        }

        if (benmchmarkName == null)

        {

            throw new ArgumentNullException("benmchmarkName");

        }

        if (computerModel == null)

        {

            throw new ArgumentNullException("computerModel");

        }

 

        User = user;

        BenmchmarkName = benmchmarkName;

        ComputerModel = computerModel;

        Score = score;

    }

}

So far there’s nothing new here. Computer configuration and benchmark will become entities themselves soon, but let’s not get ahead of ourselves.

The only interesting property at this point is the User.

[BelongsTo]

public User User { get; private set; }

It has a BelongsToAttribute to denote it points to another entity (on our case the ‘one’ end of our one-to-many).

Let’s now let our users to actually save benchmark results, and we’re more or less done:

public BenchmarkResult RunBenchmark(string benchmarkName, string computerModel, double score)

{

    var result = new BenchmarkResult(this, benchmarkName, computerModel, score);

    benchmarkResults.Add(result);

    return result;

}

Test

We now have all the logic in place, so let’s build a test:

[Fact]

public void Can_perform_benchmark_runs()

{

    var stefan = new User

    {

        Email = "stefan@gmail.com",

        Name = "Stefan",

        Password = "Super compilcated password!",

        About = "Stefan is a very cool."

    };

    stefan.RunBenchmark("Foo bar!", "AyeMack Pro", 3.2);

    stefan.Save();

 

    var user = User.FindAll().Single();

 

    Assert.NotEmpty(user.BenchmarkResults);

    Assert.Equal(1, user.BenchmarkResults.Count());

 

    var result = user.BenchmarkResults.Single();

 

    Assert.NotNull(result);

    Assert.Equal("Foo bar!", result.BenmchmarkName);

    Assert.Equal("AyeMack Pro", result.ComputerModel);

    Assert.Equal(3.2, result.Score);

}

If we run it now, it will fail. Good news is, that it does not have anything to do directly with our logic. Bad news is, that we have a passing test nonetheless, so let’s have a look at it.

Error

We get “Incorrect syntax near the keyword ‘User’.” error message. Here’s the SQL that was sent to the database:

error_sql

Looks good doesn’t it? Well not – really, User is a SQL Server keyword, as we can’t just use it as identifier – we have to escape it. To do it, we have to specify the column name explicitly, and escape it by enclosing it within two ` characters (located above tab key on my keyboard).

Yes I’m aware of hbm2ddl.keywords auto-quote. However I had some issues getting it to work with ActiveRecord. Any help doing this will be appreciated.

[BelongsTo(Column = "`User`")]

public User User { get; private set; }

Now the test will pass, and the following SQL will be generated:

ok_sql

Now that we have the correct SQL, let’s look at what our schema looks like:

schema_inverse_true

Learning in the Open: I – Starting with ActiveRecord

We’re building an application to gather and compare performance metrics of various laptop configurations in given set of benchmarks. As such we’re going to start with certain set of entities, first of which will be the User. We’ll start off by defining our User entity, configuring ActiveRecord, and some basic tests.

Getting started

First thing’s first – we need to get ourselves a fresh version of required libraries. At this point in time I’m using the trunk version. You can get the latest binaries here. Everything I show here will work with ActiveRecord 2.1 final version though.

So let’s create ourselves a new solution, with class library and add required references:

references

We need Castle.ActiveRecord.dll, Castle.ActiveRecord.Linq.dll, which is where integration with NHibernate.Linq lives, and NHibernate.dll. Having that in place we can start coding our first entity.

User is always right

Let’s start by declaring our User class:

[ActiveRecord]

public class User : ActiveRecordLinqBase<User>

{

}

We mark our class with ActiveRecordAttribute. By doing this we let Active Record know that this class is persistent. We use ActiveRecordLinqBase<User> as our base class. This gives us access to all standard Active Record pattern methods, as well as IQueryable<User> so that we can use LINQ to query for our users. Alternatively if we didn’t want to have this base class we can use ActiveRecordMediator<User> which provides the same persistence services as our base class.

Now, that we told ActiveRecord it should persist our User class, we’ll need a primary key property.

private Guid id;

 

[PrimaryKey(Access = PropertyAccess.NosetterCamelcase)]

public Guid Id

{

    get { return id; }

}

Couple of things to notice about this piece of code. We use PrimaryKeyAttribute to mark our property as holding primary key. Also we use Guid as our surrogate primary key type, for several reasons. If you’ve used older versions of ActiveRecord, you may notice I didn’t specify primary key generator kind. ActiveRecord 2.1 will infer it from property type and will use guid.comb. We also don’t expose setter for this property. By using PropertyAcess.NosetterCamelcase we tell ActiveRecord to use getter to retrieve value of this property, and to use backing field which has identical name as the property, but written in camel case to write it.

We’re going to need a couple of other properties for our users:

[Property(Unique = true, NotNull = true)]

public string Name { get; set; }

 

[Property]

public string Email { get; set; }

We use PropertyAttribute to mark properties that should be persisted. While we don’t put any non default constraints on the Email property at this point, we’ll make user name unique, and we’ll disallow nulls.

[Property(Access = PropertyAccess.FieldCamelcase)]

public string Password { set { password = Hash(value); } }

 

[Property(Length = 10000)]

public string About { get; set; }

For password we expose only setter. Also since we don’t want to store passwords of our users, we hash it, and store the hash. About is a property that has Length set to 10000. This means nvarchar(max) for SQL Server 2005 (which is what we’ll use) or corresponding data type if you use other database engine.

Let’s set up a test project for ourselves and start writing some basic logic. But before we do this, we’ll need to set up a database and configure ActiveRecord.

Configuration

For our database we’ll use SQL Server .mdf file. When we create it, we’ need to create an AppDomain configuration file and put some basic configuration in it. We could alternatively put ActiveRecord configuration in some other file it we wanted.

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

  <configSections>

    <section name="activerecord"

             type="Castle.ActiveRecord.Framework.Config.ActiveRecordSectionHandler, Castle.ActiveRecord" />

  </configSections>

    <connectionStrings>

        <add name="Wawel"

             connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=f:\ComputerBenchmark\sql\Wawel.mdf;Integrated Security=True;User Instance=True"

             providerName="System.Data.SqlClient" />

    </connectionStrings>

  <activerecord pluralizeTableNames="true">

    <config database="MsSqlServer2005"

            connectionStringName="Wawel" />

  </activerecord>

</configuration>

We start by declaring active record section and registering handler for it. We then put standard Active Record configuration. We tell it to pluralizeTableNames, so that for our User class a Users table will be created. We then specify what kind of database engine we want to use (MsSqlServer2005) and name of the connection string to use. That’s it. If you’ve used previous versions of ActiveRecord you may remember it used to require quite a bit more configuration. Now it will just use default values for these, which you can always override if you want. We can now move on to creating tests.

Tests

We’ll use XUnit.NET as our testing framework. Sine ActiveRecord is built on top of NHibernate we also use NHProf to gain insight into what’s going on under the cover. Here’s the setup code.

public class UserTests:IDisposable

{

    public UserTests()

    {

        // performs initialization using information from appdomain config file

        ActiveRecordStarter.Initialize();

        // registers all active record types from the assembly

        ActiveRecordStarter.RegisterAssemblies(typeof(User).Assembly);

        // generates database schema

        ActiveRecordStarter.UpdateSchema();

 

        NHibernateProfiler.Initialize();

    }

 

    public void Dispose()

    {

        NHibernateProfiler.Stop();

        ActiveRecordStarter.DropSchema();

 

        // this is only for tests

        ActiveRecordStarter.ResetInitializationFlag();

    }

}

ActiveRecordStarter.Initialize reads all settings from the app.config file we discussed above and initializes its engine. We then feed it with information about our Active Record classes, and call UpdateSchema. ActiveRecord will now generate our complete database schema for us.

sshot-2

As you can see table name is nicely pluralized, and all the information we specified in attributes was used to create correct schema. Having that, we can now create our first test.

[Fact]

public void Can_save_and_read_User()

{

    var stefan = new User

    {

        Email = "stefan@gmail.com",

        Name = "Stefan",

        Password = "Super compilcated password!",

        About = "Stefan is a very cool."

    };

 

    stefan.Save();

    var users = User.Queryable

        .Where(u => u.Name.StartsWith("S"))

        .ToList();

    Assert.NotEmpty(users);

    Assert.Equal("Stefan", users.Single().Name);

}

We create a user, than call method Save, inherited from our base class which persists the user to the database. We then can use static Queryable property which exposes LINQ engine to create a fancy LINQ query to retrieve our user.

sshot-3

Fantastic! We have a working persistent user entity!

Learning in the open – Sample application for Castle stack

We’re getting really close to new release of major Castle Project elements (Monorail 2.0, ActiveRecord 2.1, Windsor 2.1…). Coincidently I started building a small application on top of the stack, and I thought it would be a good idea to make this a “learning in the open” experience, and share my progress on this blog.

This will mostly (at least initially) be a rework of Ayende’s old series, but I will update it to the latest version of the projects and try to discuss some new features as we go along.

I don’t have the application ready yet. This is a journey for me, and as I don’t really have much experience with either Monorail or ActiveRecord, I may do stupid things. That’s the part where your feedback comes into play. I want to drive this series on feedback in much greater degree than the series on Dynamic Proxy. If you want me to dive into details on certain topics – let me know. If you think I should have done something differently and revisit some parts – let me know.

That’s all for now – see you next time.