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.

[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!


Posted 01-10-2010 9:27 PM by Krzysztof Koźmic
Filed under:

[Advertisement]

Comments

Kiran wrote re: Learning in the Open: I – Starting with ActiveRecord
on 01-11-2010 8:08 AM

Hash method you used for password, is it some custom implementation or is this from Castle?

Krzysztof Kozmic wrote re: Learning in the Open: I – Starting with ActiveRecord
on 01-11-2010 8:41 AM

Kiran,

I used SHA1 impl.  from BCL

Blair wrote re: Learning in the Open: I – Starting with ActiveRecord
on 01-15-2010 10:45 PM

Is the stefan object for Stefan Seddich if it is thats cool he is a good friend of mine :)

Blair

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)