José F. Romaniello

Las aventuras y desventuras de un codificador.

In this post I will map the same domain I used in the previous post about EntityFramework but without the overhead of the crazy properties I had to add to fix the deficiencies of EntityFramework 4.1:

2011-03-29_2015_001

For this post I’m using the following nugets:

  • ConfORM (depends on NHibernate): This help me to automap the domain to a relational model based on conventions.
  • NHibernate.LinFu: This is a proxy generator used by nhibernate for lazy loading. Note that the next version of NHibernate 3.2 (trunk) doesn’t need this. It is inside NHibernate.dll
  • NHibernate.SetForNet4: This is because NHibernate doesn’t support System.Collections.Generic.ISet<T> out of the box. ISet<T> is from .Net 4, while nhibernate support set mapping from version 1 with Iesi.Collections. This nuget add support for lazy loading an ISet<T>

This is a console project and I have the following files:

2011-03-31_1047

Net4Collections is a class installed by the NHibernate.SetForNet4, so the only I did for this example was:

internal class Program
{
    private static void Main()
    {
        HbmMapping mappings = AutomapDomain(typeof (Order),
                                            typeof (OrderItem),
                                            typeof (Product),
                                            typeof (Customization));

        Configuration configuration = ConfigureNHibernate(mappings);
        Console.WriteLine("Generating the schema");
        new SchemaExport(configuration).Create(true, true);

        Console.WriteLine("Persiting some objects");
        var sf = configuration.BuildSessionFactory();
        
        using(var s = sf.OpenSession())
        using(var tx = s.BeginTransaction())
        {
            s.Save(new Product
                       {
                           Name = "Fideos",
                           Customizations = {new Customization
                                                 {
                                                     Name = "Tuco",
                                                     PossibleValues = {"Pocon", "Medio", "Sopa"}
                                                 }}
                       });
            tx.Commit();
        }
        Console.ReadLine();
    }

    private static HbmMapping AutomapDomain(params Type[] entities)
    {
        var orm = new ObjectRelationalMapper();
        //We are telling here to conform that ISet<> properties should be mapped as <set>
        orm.Patterns.Sets.Add(
            m => m.GetPropertyOrFieldType()
                  .GetGenericIntercafesTypeDefinitions()
                  .Contains(typeof (ISet<>)));

        orm.TablePerClass(entities);
        CustomizeMappings(orm);

        //Some ConfORM.Shop patterns
        var englishInflector = new EnglishInflector();
        var patterns = new SafePropertyAccessorPack()
            .Merge(new CoolTablesAndColumnsNamingPack(orm))
            .Merge(new PluralizedTablesPack(orm, englishInflector)
            .Merge(new CollectionOfElementsColumnApplier(orm, englishInflector)));

        //Mapper
        var mapper = new Mapper(orm, patterns);

        var mapping = mapper.CompileMappingFor(entities);
        Console.WriteLine(Serialize(mapping));
        return mapping;

    }

    private static void CustomizeMappings(ObjectRelationalMapper orm)
    {
        orm.PersistentProperty<Order>(o => o.Total);
        orm.Cascade<Product, Customization>(Cascade.All);
    }

    private static Configuration ConfigureNHibernate(HbmMapping mapping)
    {
        var configuration = new Configuration();

        //nhibernate support for ISet<>
        configuration.CollectionTypeFactory<Net4CollectionTypeFactory>();

        //Use linfu proxy facotory: NOTE: This is going to be deprecated in vNext.
        configuration.Proxy(p => p.ProxyFactoryFactory<ProxyFactoryFactory>());

        //The database connection configuration
        configuration.DataBaseIntegration(db =>
                                              {
                                                  db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
                                                  db.Dialect<MsSql2008Dialect>();
                                                  db.Driver<SqlClientDriver>();
                                                  db.ConnectionStringName = "NHibernateTest";
                                                  db.LogSqlInConsole = true;
                                                  db.LogFormatedSql = true;
                                              });


        configuration.AddDeserializedMapping(mapping, "AllMappings");

        return configuration;
    }

    //This method is only used to show you in the console the nhibernate mappings in XML 
    protected static string Serialize(HbmMapping hbmElement)
    {
        var setting = new XmlWriterSettings {Indent = true};
        var serializer = new XmlSerializer(typeof (HbmMapping));
        using (var memStream = new MemoryStream())
        using (XmlWriter xmlWriter = XmlWriter.Create(memStream, setting))
        {
            serializer.Serialize(xmlWriter, hbmElement);
            memStream.Flush();
            memStream.Position = 0;

            var sr = new StreamReader(memStream);
            return sr.ReadToEnd();
        }
    }
}

There are only one customization in this example to map the readonly property. By default ConfORM doesn’t map readonly properties but as I said yesterday I was trying to do so in EntityFramework…
I am using a set of conventions to map the domain, the power of ConfORM to infer most of the things and also ConfORM.Shop.dll that comes with the ConfORM nuget package to generate this beautiful schema:

2011-03-31_1115

Please take your time to examine this schema.

Want to see the output of the console?

Generating the schema

    if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FK3E8588581FEFE3AB]') AND parent_object_id = OBJECT_ID('OrderItems'))
alter table OrderItems  drop constraint FK3E8588581FEFE3AB


    if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FK3E858858F373BEAE]') AND parent_object_id = OBJECT_ID('OrderItems'))
alter table OrderItems  drop constraint FK3E858858F373BEAE


    if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKEF9298D4286FF938]') AND parent_object_id = OBJECT_ID('OrderItemPreferences'))
alter table OrderItemPreferences  drop constraint FKEF9298D4286FF938


    if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKC2F496971FEFE3AB]') AND parent_object_id = OBJECT_ID('Customizations'))
alter table Customizations  drop constraint FKC2F496971FEFE3AB


    if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FK956AE80DAF824711]') AND parent_object_id = OBJECT_ID('CustomizationPossibleValues'))
alter table CustomizationPossibleValues  drop constraint FK956AE80DAF824711


    if exists (select * from dbo.sysobjects where id = object_id(N'Orders') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Orders

    if exists (select * from dbo.sysobjects where id = object_id(N'OrderItems') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table OrderItems

    if exists (select * from dbo.sysobjects where id = object_id(N'OrderItemPreferences') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table OrderItemPreferences

    if exists (select * from dbo.sysobjects where id = object_id(N'Products') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Products

    if exists (select * from dbo.sysobjects where id = object_id(N'Customizations') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Customizations

    if exists (select * from dbo.sysobjects where id = object_id(N'CustomizationPossibleValues') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table CustomizationPossibleValues

    if exists (select * from dbo.sysobjects where id = object_id(N'hibernate_unique_key') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table hibernate_unique_key

    create table Orders (
        Id BIGINT not null,
       [Date] DATETIME null,
       Status INT null,
       Location INT null,
       primary key (Id)
    )

    create table OrderItems (
        Id BIGINT not null,
       ProductId BIGINT null,
       Quantity INT null,
       UnitPrice DECIMAL(19,5) null,
       OrderId BIGINT null,
       primary key (Id)
    )

    create table OrderItemPreferences (
        OrderItemId BIGINT not null,
       Preference NVARCHAR(255) null,
       idx NVARCHAR(255) not null,
       primary key (OrderItemId, idx)
    )

    create table Products (
        Id BIGINT not null,
       Name NVARCHAR(255) null,
       Price DECIMAL(19,5) null,
       primary key (Id)
    )

    create table Customizations (
        Id BIGINT not null,
       Name NVARCHAR(255) null,
       ProductId BIGINT null,
       primary key (Id)
    )

    create table CustomizationPossibleValues (
        CustomizationId BIGINT not null,
       PossibleValue NVARCHAR(255) null
    )

    alter table OrderItems 
        add constraint FK3E8588581FEFE3AB 
        foreign key (ProductId) 
        references Products

    alter table OrderItems 
        add constraint FK3E858858F373BEAE 
        foreign key (OrderId) 
        references Orders

    alter table OrderItemPreferences 
        add constraint FKEF9298D4286FF938 
        foreign key (OrderItemId) 
        references OrderItems

    alter table Customizations 
        add constraint FKC2F496971FEFE3AB 
        foreign key (ProductId) 
        references Products

    alter table CustomizationPossibleValues 
        add constraint FK956AE80DAF824711 
        foreign key (CustomizationId) 
        references Customizations

    create table hibernate_unique_key (
         next_hi BIGINT 
    )

    insert into hibernate_unique_key values ( 1 )
Persiting some objects
NHibernate: 
    select
        next_hi 
    from
        hibernate_unique_key with (updlock,
        rowlock)
NHibernate: 
    update
        hibernate_unique_key 
    set
        next_hi = @p0 
    where
        next_hi = @p1;
    @p0 = 2 [Type: Int64 (0)], @p1 = 1 [Type: Int64 (0)]
NHibernate: 
    select
        next_hi 
    from
        hibernate_unique_key with (updlock,
        rowlock)
NHibernate: 
    update
        hibernate_unique_key 
    set
        next_hi = @p0 
    where
        next_hi = @p1;
    @p0 = 3 [Type: Int64 (0)], @p1 = 2 [Type: Int64 (0)]
NHibernate: 
    INSERT 
    INTO
        Products
        (Name, Price, Id) 
    VALUES
        (@p0, @p1, @p2);
    @p0 = 'Fideos' [Type: String (4000)], @p1 = 0 [Type: Decimal (0)], @p2 = 32768 [Type: Int64 (0)]
NHibernate: 
    INSERT 
    INTO
        Customizations
        (Name, Id) 
    VALUES
        (@p0, @p1);
    @p0 = 'Tuco' [Type: String (4000)], @p1 = 65536 [Type: Int64 (0)]
NHibernate: 
    UPDATE
        Customizations 
    SET
        ProductId = @p0 
    WHERE
        Id = @p1;
    @p0 = 32768 [Type: Int64 (0)], @p1 = 65536 [Type: Int64 (0)]
NHibernate: 
    INSERT 
    INTO
        CustomizationPossibleValues
        (CustomizationId, PossibleValue) 
    VALUES
        (@p0, @p1);
    @p0 = 65536 [Type: Int64 (0)], @p1 = 'Pocon' [Type: String (4000)]
NHibernate: 
    INSERT 
    INTO
        CustomizationPossibleValues
        (CustomizationId, PossibleValue) 
    VALUES
        (@p0, @p1);
    @p0 = 65536 [Type: Int64 (0)], @p1 = 'Medio' [Type: String (4000)]
NHibernate: 
    INSERT 
    INTO
        CustomizationPossibleValues
        (CustomizationId, PossibleValue) 
    VALUES
        (@p0, @p1);
    @p0 = 65536 [Type: Int64 (0)], @p1 = 'Sopa' [Type: String (4000)]

In this domain we have things like ISet and IDictionary (the OrderItemPreferences table).
It is a quite simple example but as you can see ConfORM resolve most of the things *automagicallly although you can customize everything.

There is also an inflector for Spanish and Italian in ConfORM.Shop. You don’t need an inflector to work with ConfORM you can remove all that part and use singular names.

I'll publish this example somewhere soon. But if you need to get into ConfORM I strongly recommend you to see the ConfOrm.UsageExamples and also NHibernate.Mystic.

I did a lot of corrections to this article after published; thank Fabio Maulo very much for doing a deep review.

| More

This is my experience with EF 4.1 Code First so far. It may be useful for you given my background in NHibernate.

I am not trying to start a rant against it. Just to highlight the state of the art; and how you might overcome to some problems.

The domain I tried to map was this:

2011-03-29_2015

Four classes, Two enums.

I just want to keep this clear; I will talk about very simple cases. I know that I can handle really really convoluted scenarios with NHibernate as ORM but I will talk about the most common scenarios I have seen.

Swallowing exceptions

This is one of the most irritating things. I’ve seen two cases for this so far:

  • If you don’t set a connection string or your connection string name is wrong. EntityFramework doesn’t throw. Instead it creates a new database in the sqlexpress instance; named with the full namespace of the DbContext. Accessing with trusted connection of course. I’d expect rather something like this:

2011-03-29_2026

  • If you have sealed properties; everything will work. It is even going to save an object with a many-to-one relationship with the right values in the database and it will load the object back. Surprisingly the reference will be null instead of a proxy (this is obviously for lazy loading stuff). NHibernate will throw by default an exception given you a list of the sealed methods;

2011-03-29_2034

Of course you can disable this to speed up the built of the session factory but that is pointless because it is supposed to happen once.

In my humble opinion they should have more care with those things if you don’t want to annoy developers with odd results.

Possible workaround

There is not; this is EF internals. If you don’t want to deal with “virtual” thing and make everything virtual you should definitely take a look to Virtuosity; a project from my friend Simon.

Logging facilities

There is no way to have a look what commands are going to the database. This is widely used in the NHibernate world and you have two ways by simply using show_sql = true or using a logging framework like log4net.

Possible workaround

There are some hacks; like wrapping the database connection provider; as explained here but it didn’t work for me. The other thing you can do is to use EfProf, this is a commercial product and serve for a wide range of purposes.

Lack of good identifiers generators

EntityFramework support two kind of Persistent Object ID generation techniques; identity and assigned.  NHibernate 2.1 have 17 techniques for generating your POID (article from 2009) and  the two most discouraged patterns are; identity and assigned. This is not a minor thing for an ORM:

Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.

At some point this means that you will be sending the operations as a batch when flushing. But “identity” in sql server is a bad strategy because you don’t know the ID before inserting the record; you need to insert the record and then you can ask for the ID (or the last id). Even Sequences (in most of the DBMS) work better because you can pull numbers without inserting anything.

Keep in mind that EntityFramework work quite different than NHibernate regarding this:

  • NHibernate ensure than the Save method (before flushing to the database) will put an ID in the entity, so you can operate with the entity ID before flushing the changes. This is very important when you use a pattern like session-per-request; because you will probably use the ID for something else like generating a link.
  • EntityFramework ensure the unit of work works as unit and will not give you the ID before flushing the changes.

What is the best? I am not sure because identity is a very bad thing despite how you use it. It is not an ORM problem is just bad and any DBA will agree on this.

Posible workarounds

This is easy to fix in the current status of EntityFramework. Don’t use identity:

modelBuilder.Conventions.Remove<StoreGeneratedIdentityKeyConvention>();

and EntityFramework will think that you are going to use assigned. From here you have two paths:

  • If you don’t want to generate human-readable values; stick to GUID and use something like this in the constructor of the entity:
public EntityBase
{
  public EntityBase()
  {
     Id = Guid.NewGuid()
  }
  public Guid Id { get; set; }
}

We are generating a Guid in the constructor; every entity will have an Id before flushing and… when you load an entity EF will put the right id (that comes from the database) in the ID property after constructing the instance.

  • If you want to generate human-readable values; I encourage you to use the HiLo algorithm. Fortunately I write a post some days ago. I been working in this and I’ve enhanced the design of that classes but I will not publish yet until I get something more mature.

Lack of customizable mapping types

NHibernate has a really important extension point; the interface IUserType. I use at least one custom implementation in every project. What does this interface? Is pretty simpler; It allows you to describe how a value will be read and write to/from the database.

Let’s say that you are working on legacy database and it uses “N” and “S” (from Spanish “si” = “yes”). You can map this to a char property on .Net but it is not right because the true meaning of this in the c# language would be “System.Boolean”. So NHiberante allows you to decouple the database implementation from the object oriented implementation.

The same thing is used for mapping enums to the database. NHibernate comes with a handy collection of useful user types.

There is another interface named ICompositeUserType that allows to map a property to multiple columns in the database; it is not widely used/known though.

Possible workarounds

It is ugly, but for mapping enums I did something like this:

#region EntityFramework Specific
[Obsolete("EntityFramework can't map enums.")]
public virtual string StatusString
{
    get { return Status.ToString(); }
    set
    {
        OrderStatus newValue;
        if (Enum.TryParse(value, out newValue))
        {
            Status = newValue;
        }
    }
}
#endregion

public virtual OrderStatus Status { get; set; }

Lack of Read-Only properties

ReadOnly properties in NHibernate means than the value is going to be saved and updated in the database but it will never be read from the database because it is a read-only property:

public decimal Total
{
  get{
    Items.Sum(i => i.Quantity * i.Price);
  }
}

There is a full explanation here, from my friend Germán Schuager.
This most of the time means a de-normalization of the database; but it is quite right because you will be saving the total of an invoice almost always for sure.

Possible workaround

Carlos Peix illuminated me in twitter:

2011-03-29_2132

Yes! Carlos you were right:

public decimal Total
{
  get{
    Items.Sum(i => i.Quantity * i.Price);
  }
  set{ 
     // no op 
  }
}

we can fool EntityFramework this way.

Lack of collection of Elements

This means that EntityFramework doesn’t currently support ISet<string>, ICollection<string> or ISet<int> as property. NHibernate support this from earlier versions. It will simply use another table for storing the elements. You can have even collection of enums because it will use the same mechanism for every type; a plain IUserType as explained above.

NHibernate also support collection of components; entities without meaning outside like Address or telephone.

Possible workaround

I’ve used for the above domain some kind of de-normalization and serialization/parsing;

[Obsolete("EntityFramework doesn't store collection of elements.")]
public virtual string CommaSepparatedPossibleValues
{
    get { return string.Join(",", possibleValues); }
    set
    {
        if(value == null) return;
        value.Split(',')
             .ToList()
             .ForEach(v => possibleValues.Add(v));
    }
}

Lack of MAP mapping or Dictionary mapping

The term “map” come from the java world; while in .Net map means exactly Dictionary. NHibernate can handle a widely variety of dictionaries:

  • Element as Key, Element as Value
  • Element as Key, Component as Value
  • Element as Key, Entity (many-to-many) as value
  • Component as Key, Element as Value
  • Component as Key, Component as Value
  • Component as Key, Entity (many-to-many) as value
  • Entity (many-to-many) as Key, Element as value
  • Entity (many-to-many) as Key, Component as value
  • Entity (many-to-many) as Key, Entity as value

This is very well explained here. 

Possible workaround

There isn’t. The domain has only one case of IDictionary<string, string>. I handle with something very similar to the previous workaround.

The cost of the workarounds

Most of these workarounds come with a price.

  • You will not be able to query in those properties by sure.
  • You will pollute your entities with weird properties, like an empty set (in a read-only property) or two properties for converting something.

Non-technical issues

Lack of documentation

There is a bad combination between long release cycles with a product that is pushed by a big company and has lot of people around writing articles on alphas, betas and so on. If you do a google search for something you will find a variety of API that are not currently supported. You can try this right now do a search for:

  • disable identity generator
  • generating the database schema
  • mapping a many to many

I can’t really understand why people say than this is a pro on EntityFramework right now. Even the MSDN documentation doesn’t match the current programming API.

On the other hand NHibernate has a good reference documentation and lot of posts with working examples. In fact; when lurking for a problem sometimes I found the answer in the hibernate reference documentation or even in the hibernate forums!. Is NHibernate exempt of this kind of problem? definitely no for instance NHibernate has a vocabulary that doesn’t always match with the FluentNHibernate ones; mutable=”false” in nhibernate is “ReadOnly()” in FNH. But is pretty common from bloggers to mark something as outdated. Another example is that for instance even if we have like 5 official different ways of mapping a class if you ask a question in the forum you know that you should send the official dialect: plain old xml (aka POX).

Ignoring the progress of the OpenSource community

The NHibernate/Hibernate community has decades dealing with this. Ignore them it is not the best thing.
I thought Microsoft had overcome to this;

  • Mef was one of the first in codeplex
  • Asp.Net MVC is OSS
  • The new WCF web api is OSS
  • NuGet is the new guy on the block

While EF team is trying to figure out how to create a good fluent API; NHibernate has a production-ready API since long time that work for a lot of projects ( FluentNHibernate ). It has two attribute based APIS NHibernate.Mapping.Attributes and Castle.ActiveRecord. It has a convention based API more powerful than the one it comes out of the box with EF; -because you can actually define conventions- ( FluentNHibernate AutoMappings ). And now it has a another convention based API that can read your mind; it has set of powerful conventions for inferring your mappings via reflection and a powerful set of conventions to make your DBA happy ( ConfORM ).

So, my two cents on this; is to keep an eye in the community. There are lot of clever people willing to help.

I hope you find this article interesting if you are coming from NH to EF or if you are still in NH to get an idea how are going things in EF.

If you find something wrong in one of the points made here; don’t hesitate to send me a comment, tweet, mail or whatever.

| More

I wrote a little implementation of the HiLo pattern for EntityFramework. Those who are using NHibernate currently already knows how this pattern works but I am going to give a little explanation.

The Hi/Lo pattern describe a mechanism for generating safe-ids on the client side rather than the database. Safe in this context means without collisions. This pattern is interesting for three reasons:

  • It doesn’t break the Unit of Work pattern (check  this link and this other one)
  • It doesn’t need many round-trips as the Sequence generator in other DBMS.
  • It generates human readable identifier unlike to GUID techniques.

How it works?

The identifier generated is composed of two parts; the Hi part and the Lo part. The Hi part of the identifier is controlled by the database while the Lo part is controlled by the client side. Applications need to agree in only one parameter called “MaxLo”.

Imagine we agree to use a MaxLo of 100. Once the application needs to generate an ID for the first time; it will ask a Hi to the database; suppose the database returns “1”.  Now the application knows, that it can use identifiers from 1 to 100. Once the application run out of “Lo” because it hits the MaxLo; the application will ask for another Lo to the database.

NHibernate support this out of the box while EntityFramework is far from that.

Test case

I didn’t write much tests cases for this feature but this should be very descriptive:

[Test]
public void ShouldWork()
{
    var expected = Enumerable.Range(0, 200).Select(i => (long)i).ToList();

    using(var context = new SampleContext())
    {
        //create 200 products:
        var products = Enumerable.Range(0, 200)
            .Select(i => new Product {Name = string.Format("Test product {0}", i) }).ToList();
        
        //add to the dbSet: DO NOT FLUSH THE CHANGES YET.
        products.ForEach(p => context.Orders.Add(p));
        
        //Assert
        products.Select(p => p.Id)
            .Should().Have.SameSequenceAs(expected);


        context.SaveChanges();
    }
}

First; create 200 new products; then call the method Add of the DbSet. One of the interesting things about this, is that I want the ID right when I call Add, despite if I flush the changes or no.

Solution

The first class is the HiLoGenerator:

public class HiLoGenerator<TDbContext> : IHiLoGenerator
    where TDbContext : DbContext, new()
{
    private static readonly object ConcurrencyLock = new object();
    private readonly int maxLo;
    private string connectionString;
    private long currentHi = -1;
    private int currentLo;

    public HiLoGenerator(int maxLo)
    {
        this.maxLo = maxLo;
    }

    #region IHiLoGenerator Members

    public long GetIdentifier()
    {
        long result;
        lock (ConcurrencyLock)
        {
            if (currentHi == -1)
            {
                MoveNextHi();
            }
            if (currentLo == maxLo)
            {
                currentLo = 0;
                MoveNextHi();
            }
            result = (currentHi*maxLo) + currentLo;
            currentLo++;
        }
        return result;
    }

    public void SetConnectionString(string newConnectionString)
    {
        connectionString = newConnectionString;
    }

    #endregion

    private void MoveNextHi()
    {
        using (var connection = CreateConnection())
        {
            connection.Open();
            using (var tx = connection.BeginTransaction(IsolationLevel.Serializable))
            using (var selectCommand = connection.CreateCommand())
            {
                selectCommand.Transaction = tx;
                selectCommand.CommandText =
                    "SELECT next_hi FROM entityframework_unique_key;" +
                     "UPDATE entityframework_unique_key SET next_hi = next_hi + 1;";
                currentHi = (int)selectCommand.ExecuteScalar();

                tx.Commit();
            }
            connection.Close();
        }
        
    }

    private IDbConnection CreateConnection()
    {
        using (var dbContext = new TDbContext())
        {
            var connectionType = dbContext.Database.Connection.GetType();
            connectionString = connectionString ?? dbContext.Database.Connection.ConnectionString;
            return (IDbConnection) Activator.CreateInstance(connectionType, connectionString);
        }
    }
}

This class is intented to be used as singleton; for the whole application. That’s why it has a concurrency look. The most important thing happens here:

result = (currentHi * maxLo) + currentLo;

Then we need to tweak our DbContext as follows:

public class SampleContext : DbContext
{
    private static readonly HiLoGenerator<SampleContext> HiloGenerator 
        = new HiLoGenerator<SampleContext>(100);

    private IDbSet<Product> orders;
    public IDbSet<Product> Orders
    {
        get { return orders; }
        set { orders = new HiLoSet<Product>(value, HiloGenerator); }
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<StoreGeneratedIdentityKeyConvention>();
        modelBuilder.Entity<Product>().HasKey(p => p.Id);
    }
}

And then the HiLoSet is a wrapper arround DbSet;

public class HiLoSet<T> : IDbSet<T> where T : EntityBase
{
    private readonly IDbSet<T> dbSet;
    private readonly IHiLoGenerator generator;

    public HiLoSet(IDbSet<T> dbSet, IHiLoGenerator generator)
    {
        this.dbSet = dbSet;
        this.generator = generator;
    }

    public T Add(T entity)
    {
        var add = dbSet.Add(entity);
        TrySetId(entity);
        return add;
    }

    private void TrySetId(EntityBase entity)
    {
        if (entity.Id == default(long))
        {
            entity.Id = generator.GetIdentifier();
            HandleChildsObjects(entity);
        }
    }

    private void HandleChildsObjects(EntityBase entity)
    {
        var propertyInfos = new List<PropertyInfo>();
        var typeToLook = entity.GetType();
        do
        {
            var newProps = entity.GetType()
                .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .Where(p => typeof(IEnumerable<EntityBase>).IsAssignableFrom(p.PropertyType)).ToList();
            propertyInfos.AddRange(newProps);
            typeToLook = typeToLook.BaseType;
        } while (typeToLook != typeof (object));
        

        var aggregated = propertyInfos
            .Select(p => p.GetValue(entity, null))
            .OfType<IEnumerable<EntityBase>>()
            .Where(col => col != null).SelectMany(col => col);
        foreach (var child in aggregated)
        {
            TrySetId(child);
        }
    }

    #region no op methods
        public IEnumerator<T> GetEnumerator()
        {
            return dbSet.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)dbSet).GetEnumerator();
        }

        public Expression Expression
        {
            get { return dbSet.Expression; }
        }

        public Type ElementType
        {
            get { return dbSet.ElementType; }
        }

        public IQueryProvider Provider
        {
            get { return dbSet.Provider; }
        }

        public T Find(params object[] keyValues)
        {
            return dbSet.Find(keyValues);
        }

        public T Remove(T entity)
        {
            return dbSet.Remove(entity);
        }

        public T Attach(T entity)
        {
            return dbSet.Attach(entity);
        }

        public T Create()
        {
            return dbSet.Create();
        }

        public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
        {
            return dbSet.Create<TDerivedEntity>();
        }

        public ObservableCollection<T> Local
        {
            get { return dbSet.Local; }
        }
        #endregion
}

When we call the Add method, we set the ids for the object and we even explore the child objects to do the same.
It is a hacky solution but will work for most of the cases.
That is all the code! I hope you find useful.

| More

I’ve been learning and experimenting a lot of WCF as part of my new job this week on Tellago.

Here is something that I did this week and I’ll like to share with my readers.

This post uses the WCF Web APIs Preview 3, releases on Jan 14 of 2011. The API might change in the near future.

One of the most important things about building Http-based REST services (wait! resources Guiño) is the location.

Let’s start with a pretty basic example (this is from ContactManager; the sample application at wcf.codeplex.com):

[ServiceContract]
[Export]
public class ContactsResource
{
    private readonly IContactRepository repository;

    [ImportingConstructor]
    public ContactsResource(IContactRepository repository)
    {
        this.repository = repository;
    }

    [WebGet(UriTemplate = "")]
    public List<Contact> Get()
    {
        return this.repository.GetAll();
    }

    [WebInvoke(UriTemplate = "", Method = "POST")]
    public Contact Post(Contact contact, HttpResponseMessage response)
    {
        this.repository.Post(contact);
        response.StatusCode = HttpStatusCode.Created;
        return contact;
    }
}

[ServiceContract]
[Export]
public class ContactResource
{
   private readonly IContactRepository repository;

   [ImportingConstructor]
   public ContactResource(IContactRepository repository)
   {
       this.repository = repository;
   }

   [WebGet(UriTemplate = "{id}")]
   public Contact Get(string id, HttpResponseMessage response)
   {
       var contact = this.repository.Get(int.Parse(id, CultureInfo.InvariantCulture));
       if (contact == null)
       {
           response.StatusCode = HttpStatusCode.NotFound;
           response.Content = new StringContent("Contact not found");
       }

       return contact;
   }

   [WebInvoke(UriTemplate = "{id}", Method = "PUT")]
   public Contact Put(string id, Contact contact, HttpResponseMessage response)
   {
       this.Get(id, response);
       this.repository.Update(contact);
       return contact;
   }

   [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
   public Contact Delete(string id)
   {
       var intId = int.Parse(id, CultureInfo.InvariantCulture);
       dynamic deleted = this.repository.Get(intId);
       this.repository.Delete(intId);
       return deleted;
   }
}

This article is focused in the method Post of the ContactsResource class.

The highlighted line set the status of the response to Created (Http Code = 202). In addition to that, I’d like to add to the header response the location indicating where this new “resource” is now.

We can do something like this:

response.StatusCode = HttpStatusCode.Created;
response.Header.Location = ..... + "contact/" +  contact.Id;

Where “contact” come from? Well, this is in the RouteTable, which is configured in the Global.asax.cs class as follows:

RouteTable.Routes.AddServiceRoute<ContactResource>("contact", configuration);
RouteTable.Routes.AddServiceRoute<ContactsResource>("contacts", configuration);

 

The problem

The problem with writing the route of the newly created resource in code as I did in the previous section, is not about “magic strings” or strongly-typeness; I can’t care less about magic strings because I am used to write tests. The main problem is:

  • Duplication; What is the uri template for this method? and How do I construct an Uri for this method?
  • I don’t know how is the URI template at this point without going to the method and looking at the attribute; then I’ve to go to the configuration of the routes table to see the prefix for the resource class.

The solution

I am going to use a little bit of reflection and the RouteTables to get the uri of the resource. I started with a some simple tests as follows:

[TestFixture]
public class ResourceLinkerTests
{
    public class SampleResource
    {
        [WebGet]
        public string GetSomething()
        {
            return string.Empty;
        }

        [WebGet(UriTemplate = "Zapato/{id}/{other}")]
        public string GetFoo(string id, 
                            string other, 
                            double somethingElseThanIsNotInTheRoute)
        {
            return string.Empty;
        }

        [WebInvoke]
        public void PostFoo() {}
        
        [WebInvoke(UriTemplate = "PostBar?lele={id}")]
        public void PostBar(int id) {}

        public void NotAWebMethod() {}
    }
    
    [SetUp]
    public void SetUp()
    {
        RouteTable.Routes.AddServiceRoute<SampleResource>("SuperResource", null);
    }
    
    [Test]
    public void CanGetRouteWithSimpleCase()
    {
        var uriResolver = new ResourceLinker("http://foo.bar");
        var result = uriResolver.GetUri<SampleResource>(sr => sr.GetSomething());
        result.ToString()
            .Should().Be.EqualTo("http://foo.bar/SuperResource/GetSomething");
    }


    [Test]
    public void CanGetValuatedUri()
    {
        var uriResolver = new ResourceLinker("http://foo.bar");
        var result = uriResolver.GetUri<SampleResource>(sr => sr.GetFoo("1", "2", 5467));
        result.ToString()
            .Should().Be.EqualTo("http://foo.bar/SuperResource/Zapato/1/2");
    }

    [Test]
    public void CanGetUriForWbeInvokeWithouAttribute()
    {
        var uriResolver = new ResourceLinker("http://foo.bar");
        var result = uriResolver.GetUri<SampleResource>(sr => sr.PostFoo());
        result.ToString()
            .Should().Be.EqualTo("http://foo.bar/SuperResource/PostFoo");
    }

    [Test]
    public void CanGetAnUriForWebInvokeWithUriTemplate()
    {
        var uriResolver = new ResourceLinker("http://foo.bar");
        var result = uriResolver.GetUri<SampleResource>(sr => sr.PostBar(123));
        result.ToString()
            .Should().Be.EqualTo("http://foo.bar/SuperResource/PostBar?lele=123");
    }

    [Test]
    public void WhenTheMethodIsNotAWebMethodThenThrow()
    {
        var uriResolver = new ResourceLinker("http://foo.bar");
        uriResolver.Executing(ur => ur.GetUri<SampleResource>(sr => sr.NotAWebMethod()))
                    .Throws();
    }

    [TearDown]
    public void TearDown()
    {
        RouteTable.Routes.Clear();
    }
}

As you might noticed, the SUT is the new class ResourceLinker. The SampleResource is a sample class that I use for testing the resolution of the URIs.

ResourceLinker has only one method named GetUri. I pass a lambda to the method ( Expression<Action<TResource>> ) with the parameters.

The GetFoo method has a parameter that is not included in the UriTemplate. This is really important because the Processor infrastructure of the WCF web api allows you to inject in these methods other things.

The first problem I faced was that calling AddServiceRoute within a unit test throws the following exception:

SetUp : System.InvalidOperationException : 'ServiceHostingEnvironment.EnsureServiceAvailable' cannot be invoked within the current hosting environment. This API requires that the calling application be hosted in IIS or WAS.

So, I made a wrapper around ServiceRoute as follows:

public interface IPrefixedRouteType
{
    Type ServiceType { get; }
    string RoutePrefix { get; }
}

public class LazyServiceRoute : RouteBase, IPrefixedRouteType
{
    private readonly string routePrefix;
    private readonly HttpHostConfiguration httpHostConfiguration;
    private readonly Type serviceType;
    private readonly Type webHttpServiceHostFactory;
    private readonly Lazy<ServiceRoute> lazyServiceRoute;

    public LazyServiceRoute(string routePrefix, 
                            HttpHostConfiguration httpHostConfiguration, 
                            Type serviceType)
        :this(routePrefix, httpHostConfiguration, serviceType, typeof(WebHttpServiceHostFactory))
    {}

    public LazyServiceRoute(string routePrefix, 
                            HttpHostConfiguration httpHostConfiguration, 
                            Type serviceType, 
                            Type webHttpServiceHostFactory)
    {
        this.routePrefix = routePrefix;
        this.httpHostConfiguration = httpHostConfiguration;
        this.serviceType = serviceType;
        this.webHttpServiceHostFactory = webHttpServiceHostFactory;
        lazyServiceRoute = new Lazy<ServiceRoute>(CreateServiceRoute);
    }

    private ServiceRoute CreateServiceRoute()
    {
        var hostFactory = (IConfigurableServiceHostFactory)Activator.CreateInstance(webHttpServiceHostFactory);
        hostFactory.Configuration = httpHostConfiguration;
        return new ServiceRoute(routePrefix, (ServiceHostFactoryBase)hostFactory, serviceType);
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        return lazyServiceRoute.Value.GetRouteData(httpContext);
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        return lazyServiceRoute.Value.GetVirtualPath(requestContext, values);
    }

    public Type ServiceType
    {
        get { return serviceType; }
    }

    public string RoutePrefix
    {
        get { return routePrefix; }
    }
}

This is a really simple class, it has the same constructors than the original “ServiceRoute” but it delays the creation of the ServiceRoute until the first usage as a route (see the field lazyServiceRoute). On the other hand LazyServiceRoute exposes the ServiceType and the RoutePrefix.

To get some syntax sugar I created the following extension methods to the RouteCollection:

public static class RouteTableExtensions
{
    public static void AddLazyServiceRoute<T>(
                this RouteCollection routeCollection, 
                string routePrefix, 
                HttpHostConfiguration httpHostConfiguration)
    {
        routeCollection.Add(new LazyServiceRoute(routePrefix, httpHostConfiguration, typeof(T)));
    }

    public static string GetRoutePrefixForType<T>(this RouteCollection routeCollection)
    {
        var routeServiceType = routeCollection
                                    .OfType<IPrefixedRouteType>()
                                    .FirstOrDefault(r => r.ServiceType == typeof (T));
        if(routeServiceType != null) return routeServiceType.RoutePrefix;
        return null;
    }
}

The first method is a shortcut for inserting a LazyServiceRoute to the route collection. The second one returns the prefix for a given resource type.

Finally the implementation of the ResourceLinker is pretty straightforward (despite the amount of reflection)

public interface IResourceLinker
{
    Uri GetUri<T>(Expression<Action<T>> restMethod);
}

public class ResourceLinker : IResourceLinker
{
    private readonly Uri baseUri;
    
    public ResourceLinker()
        : this(ConfigurationManager.AppSettings["BaseUri"])
    {}

    public ResourceLinker(string baseUri)
    {
        this.baseUri = new Uri(baseUri, UriKind.Absolute);
    }

    public Uri GetUri<T>(Expression<Action<T>> restMethod)
    {
        var methodCallExpression = (MethodCallExpression) restMethod.Body;
        var uriTemplateForMethod = GetUriTemplateForMethod(methodCallExpression.Method);

        var args = methodCallExpression.Method
            .GetParameters()
            .Where(p => uriTemplateForMethod.Contains("{" + p.Name + "}"))
            .ToDictionary(p => p.Name, p => ValuateExpression(methodCallExpression, p));

        var prefix = RouteTable.Routes.GetRoutePrefixForType<T>();
        var newBaseUri = new Uri(baseUri, prefix);
        var uriMethod = new UriTemplate(uriTemplateForMethod, true);
        return uriMethod.BindByName(newBaseUri, args);
    }

    private static string ValuateExpression(MethodCallExpression methodCallExpression, ParameterInfo p)
    {
        var argument = methodCallExpression.Arguments[p.Position];
        var constantExpression = argument as ConstantExpression;
        if(constantExpression != null) return constantExpression.Value.ToString();

        //var memberExpression = (argument as MemberExpression);
        var lambdaExpression = Expression.Lambda(argument, Enumerable.Empty<ParameterExpression>());
        var result = lambdaExpression.Compile().DynamicInvoke().ToString();
        return result;
    }

    private static string GetUriTemplateForMethod(MethodInfo method)
    {
        var webGet = method.GetCustomAttributes(true).OfType<WebGetAttribute>().FirstOrDefault();
        if (webGet != null) return webGet.UriTemplate ?? method.Name;

        var webInvoke = method.GetCustomAttributes(true).OfType<WebInvokeAttribute>().FirstOrDefault();
        if (webInvoke != null) return webInvoke.UriTemplate ?? method.Name;

        throw new InvalidOperationException(string.Format("The method {0} is not a web method.", method.Name));
    }
}

And the code for the Post method is:

[WebInvoke(UriTemplate = "", Method = "POST")]
public Contact Post(Contact contact, HttpResponseMessage response)
{
    this.repository.Post(contact);
    response.StatusCode = HttpStatusCode.Created;
    response.Header.Location =
       resourceLinker.Get<ContactResource>(cr => cr.Get(contact.Id, null));
    return contact;
}

(assuming you inject IResourceLinker in your resource class)

Testing

When I was about to write my first test with the IResourceLinker I tried to mock it. But then I figure out that is better to use the real implementation along with the real routes.

The first step is to extract the RouteTable configuration to another class;

public static class RouteConfigurator
{
    public static void Configure(HttpHostConfiguration configuration)
    {
        RouteTable.Routes.AddServiceRoute<ContactResource>("contact", configuration);
        RouteTable.Routes.AddServiceRoute<ContactsResource>("contacts", configuration);
    }
}

Then, we can write a base test fixture like this:

public class ResourceBaseTestFixture
{
    protected const string SampleHostRoute 
        = "http://foo.bar";
    protected IResourceLinker resourceLinker 
        = new ResourceLinker(SampleHostRoute);

    [TestFixtureSetUp]
    public void SetUp()
    {
        RouteTableConfigurator.Configure(null);    
    }

    [TestFixtureSetUp]
    public void TearDown()
    {
        RouteTable.Routes.Clear();
    }
}

And then you can test as follows:

[Test]
public void WhenPOSTingAContactThenReturn202AndTheLocationOfTheContact()
{
    //initilization and mock of the repository.

    var httpResponseMessage = new HttpResponseMessage(); 
    
    //act
    resource.Post(new Contact { .... }, httpResponseMessage);

    string locationOfTheNewContact =
        resourceLinker.GetUri<ContactResource>(cr => cr.Get(123, null)).ToString();

    httpResponseMessage.Satisfy(r => r.StatusCode == HttpStatusCode.Created
                                  && r.Headers.Location.ToString() == locationOfTheNewContact);
}

And then I realized the first thing I should write when creating a rest service will be something like this:

[Test]
public void TheRouteForPostAContactShouldBeOk()
{
    resourceLinker.GetUri<Contacts>(cr => cr.Create(null, null)).ToString()
        .Should().Be.EqualTo(SampleHostRoute + "/Contacts");
}

[Test]
public void TheRouteForRetrievingASingleContactShouldBeOk()
{
    resourceLinker.GetUri<Contact>(cr => cr.Get(123, null)).ToString()
        .Should().Be.EqualTo(SampleHostRoute + "/Contact/123");
}

But that is a matter of taste, I guess Sonrisa

Happy RESTing and stay in sync, I’ll start writing some articles about WCF.

| More

I’ve created a new nuget package; “NHibernate.SetForNet4”.

The package is only one file that will be inserted in your project. This class contains the implementation for the Set<T> and SortedSet<T>.

After you install NHibernate.SetForNet4; the only thing you have to do is to add the collection factory to your configuration as follows:

configuration.Properties[Environment.CollectionTypeFactoryClass] 
        = typeof(Net4CollectionTypeFactory).AssemblyQualifiedName; 

this is a sample mapping:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
        assembly="NHibernateSetForNet4"
        namespace="NHibernateSetForNet4">
  <class name="Person">
    <id name="Id">
      <generator class="hilo"/>
    </id>
    
    <property name="Name" />
    
    <property name="Age" />

    <set name="Tags" access="field.camelcase">
      <key column="PersonId" />
      <element column="Tag" />
    </set>

    <set name="Childs" 
        access="field.camelcase" 
        cascade="persist" 
        sort="PersonByAgeComparator">
      <key column="ParentId" />
      <one-to-many class="Person" />
    </set>

  </class>
</hibernate-mapping>

this is the class:

public class Person
{
    private readonly ISet<string> tags 
        = new HashSet<string>();
    private readonly ISet<Person> childs 
        = new SortedSet<Person>(new PersonByAgeComparator());

    public virtual int Id { get; set; }

    public virtual string Name { get; set; }

    public virtual int Age { get; set; }

    public virtual ISet<string> Tags
    {
        get { return tags; }
    }

    public virtual ISet<Person> Childs
    {
        get
        {
            return childs;
        }
    }
}

ISet<T>, HashSet<T> and SortedSet<T> are from System.Collections.Generics (.Net 4).

All these tests are green:

[TestFixture]
public class Fixture
{
    private ISessionFactory sessionFactory;
    private int personId;

    [TestFixtureSetUp]
    public void SetUp()
    {
        var configuration = new Configuration();
        configuration.Properties[Environment.CollectionTypeFactoryClass]
                = typeof(Net4CollectionTypeFactory).AssemblyQualifiedName;
        configuration.Configure();
        

        var schemaExport = new SchemaExport(configuration);
        schemaExport.Execute(true, true, false);
        sessionFactory = configuration.BuildSessionFactory();
        InitializeData();
    }

    private void InitializeData()
    {
        using (var s = sessionFactory.OpenSession())
        using (var tx = s.BeginTransaction())
        {
            var person = new Person
            {
                Name = "Pipo"
            };
            person.Childs.Add(new Person { Name = "Jose", Age = 1 });
            person.Childs.Add(new Person { Name = "Juan", Age = 5 });
            person.Childs.Add(new Person { Name = "Francisco", Age = 10 });

            person.Tags.Add("one");
            person.Tags.Add("two");
            person.Tags.Add("three");

            s.Persist(person);
            personId = person.Id;
            tx.Commit();
        }
    }

    [Test]
    public void CanGetAPersonWithTags()
    {
        using(var s = sessionFactory.OpenSession())
        using (s.BeginTransaction())
        {
            var person = s.Get<Person>(personId);
            person.Tags.Should().Have.SameValuesAs("one", "two", "three");
        }
    }
    
    [Test]
    public void SortedSetShouldWork()
    {
        using (var s = sessionFactory.OpenSession())
        using (s.BeginTransaction())
        {
            var person = s.Get<Person>(personId);
            person.Childs
                .Select(p => p.Age).ToArray()
                .Should().Have.SameSequenceAs(10, 5, 1);
        }
    }


    [Test]
    public void LazyLoadShouldWork()
    {
        using (var s = sessionFactory.OpenSession())
        using (s.BeginTransaction())
        {
            var person = s.Get<Person>(personId);
            s.Statistics.EntityCount.Should().Be.EqualTo(1);
            person.Childs.ToArray();
            s.Statistics.EntityCount.Should().Be.EqualTo(4);

        }
    }
}

The implementation of the proxy collections is a copy from the Iesi version. Let me know if you find some bug. The raw code is here.

Note: you still need Iesi.Collections.dll somewhere because nhibernate internals are tied to these collections, but you don’t longer need to reference it in your domain.

| More

First of all, I just pushed to Nuget two code-only packages in addition to Jose.MVC.Windsor:

For this example I’d use the Chinook sample database.

Start a new project:

2011-03-07_1338

Then, I’d use the following nuget packages:

  • Jose.MVC.Windsor; this install the basic artifacts to working with Castle.Windsor in Asp.Net MVC.
  • Jose.SessionPerRequest.NHibernate; base classes to work with the Session Per Request pattern.
  • Jose.DataAccessObject.NHibernate; interface and implementation of a simple data access object.

Within Visual Studio you can use the Add Library Package Reference or the Package Manager Console, the output will be like this:

PM> install-package Jose.MVC.Windsor
'Castle.Windsor (≥ 2.5.2)' not installed. Attempting to retrieve dependency from source...
Done
'Castle.Core (≥ 2.5.2)' not installed. Attempting to retrieve dependency from source...
Done
'WebActivator (≥ 1.4)' not installed. Attempting to retrieve dependency from source...
Done
Successfully installed 'Castle.Core 2.5.2'
Successfully installed 'Castle.Windsor 2.5.2'
Successfully installed 'WebActivator 1.4'
Successfully installed 'Jose.MVC.Windsor 1.0.0'
Successfully added 'Castle.Core 2.5.2' to ChinookWithNugets
Successfully added 'Castle.Windsor 2.5.2' to ChinookWithNugets
Successfully added 'WebActivator 1.4' to ChinookWithNugets
Successfully added 'Jose.MVC.Windsor 1.0.0' to ChinookWithNugets

PM> install-package Jose.SessionPerRequest.NHibernate
'NHibernate (≥ 3.0.0)' not installed. Attempting to retrieve dependency from source...
Done
'Iesi.Collections (≥ 1.0.1)' not installed. Attempting to retrieve dependency from source...
Done
'Antlr (≥ 3.1.3.42154)' not installed. Attempting to retrieve dependency from source...
Done
Successfully installed 'Iesi.Collections 1.0.1'
Successfully installed 'Antlr 3.1.3.42154'
'Castle.Core 2.5.2' already installed
Successfully installed 'NHibernate 3.0.0.2001'
Successfully installed 'Jose.SessionPerRequest.NHibernate 1.0.0'
Successfully added 'Iesi.Collections 1.0.1' to ChinookWithNugets
Successfully added 'Antlr 3.1.3.42154' to ChinookWithNugets
ChinookWithNugets already has a reference to 'Castle.Core 2.5.2'
Successfully added 'NHibernate 3.0.0.2001' to ChinookWithNugets
Successfully added 'Jose.SessionPerRequest.NHibernate 1.0.0' to ChinookWithNugets

PM> install-package Jose.DataAccessObjects.NHibernate
'Iesi.Collections 1.0.1' already installed
'Antlr 3.1.3.42154' already installed
'Castle.Core 2.5.2' already installed
'NHibernate 3.0.0.2001' already installed
Successfully installed 'Jose.DataAccessObjects.NHibernate 1.0.0'
ChinookWithNugets already has a reference to 'Iesi.Collections 1.0.1'
ChinookWithNugets already has a reference to 'Antlr 3.1.3.42154'
ChinookWithNugets already has a reference to 'Castle.Core 2.5.2'
ChinookWithNugets already has a reference to 'NHibernate 3.0.0.2001'
Successfully added 'Jose.DataAccessObjects.NHibernate 1.0.0' to ChinookWithNugets

Now you need to do some manual steps:

1-Fix the registration of the HttpModules in the web.config to something like this:

<add name="SessionPerRequest" type="ChinookWithNugets.Infrastructure.SessionManagement.NHibernateSessionModule, ChinookWithNugets" />

2-Add a new connection string in the web.config:

<configuration>
  <appSettings>
        .....
  </appSettings>
  <connectionStrings>
    <add name="Chinook" connectionString="Server=.\sqlexpress; User=test; Password=test; Database=Chinook" />
  </connectionStrings>
  ....

3-Create an installer for Daos, in Infrastructure\Installers\ , the code as follows:

using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using ChinookWithNugets.Data;

namespace ChinookWithNugets.Infrastructure.Installers
{
    public class DaoInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(Component.For(typeof (IDao<>))
                                        .Forward(typeof (IDaoReadOnly<>))
                                        .ImplementedBy(typeof (Dao<>)));
        }
    }
}

4-Create an installer for NHibernate:

using System.Collections.Generic;
using System.Web;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;
using Castle.Windsor;
using ChinookWithNugets.Infrastructure.SessionManagement;
using NHibernate;
using NHibernate.ByteCode.Castle;
using NHibernate.Cfg;
using NHibernate.Cfg.Loquacious;
using NHibernate.Dialect;

namespace ChinookWithNugets.Infrastructure.Installers
{
    public class NHibernateInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(Component.For<ISessionFactory>()
                    .UsingFactoryMethod(k => BuildSessionFactory()));

            container.Register(Component.For<ISessionFactoryProvider>().AsFactory());

            container.Register(Component.For<IEnumerable<ISessionFactory>>()
                                        .UsingFactoryMethod(k => k.ResolveAll<ISessionFactory>()));

            HttpContext.Current.Application[SessionFactoryProvider.Key]
                            = container.Resolve<ISessionFactoryProvider>();
        }

        private ISessionFactory BuildSessionFactory()
        {
            var configuration = new Configuration();
            configuration.DataBaseIntegration(db =>
            {
                db.Dialect<MsSql2008Dialect>();
                db.ConnectionStringName = "Chinook";
            });
            configuration.Properties[Environment.CurrentSessionContextClass]
                            = typeof (LazySessionContext).AssemblyQualifiedName;

            configuration.Proxy(p => p.ProxyFactoryFactory<ProxyFactoryFactory>());

            configuration.AddAssembly(GetType().Assembly);

            return configuration.BuildSessionFactory();
        }
    }
}

5-Create the Album class in

namespace ChinookWithNugets.Domain
{
    public class Album
    {
        public string Title { get; set; } 
    }
}

6-Create a mapping for albums Album.hbm.xml in "Data\Mappings":

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   namespace="ChinookWithNugets.Domain"
                   assembly="ChinookWithNugets">
  <class name="Album">
    <id column="AlbumId">
      <generator class="identity" />
    </id>
    <property name="Title" />
  </class>
</hibernate-mapping>

7-Create a HomeController in the Controllers folder:

using System.Linq;
using System.Web.Mvc;
using ChinookWithNugets.Data;
using ChinookWithNugets.Domain;

namespace ChinookWithNugets.Controllers
{
    public class HomeController : Controller
    {
        private readonly IDao<Album> daoAlbums;

        public HomeController(IDao<Album> daoAlbums)
        {
            this.daoAlbums = daoAlbums;
        }

        public ActionResult Index()
        {
            var albums = daoAlbums.RetriveAll().ToList();
            return View(albums);
        }
   }
}

8-Create a Index view in Views\Home:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<List<ChinookWithNugets.Domain.Album>>" %>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <ul>
    <% foreach(var a in Model) { %>
        <li><%= a.Title %></li>
    <% } %>
    </ul>
</body>
</html>

9-Run! you have now a sample ASp.Net MVC application with NHibernate and Castle.Windsor fully integrated.

2011-03-07_1853

If you want to see the full code; it is here.

IMPORTANT NOTE: unfortunately now you have to do an extra step, regarding internals stuff of the NHibernate project. Install the NHibernate.Castle package…

| More

This is my very first code-only package for nuget.

This nuget serves as a mere example on how to integrate Castle Windsor to an ASP.Net MVC application.

First create an Asp.Net MVC project:

2011-03-05_2206

The Empty is ok:

2011-03-05_2208

Then add a View and a Controller as shown:

2011-03-05_2212

Use the “Add Library Package Reference”:

2011-03-05_2239

Search for my nuget (the name for now is Jose.MVC.Windsor);

2011-03-05_2215

Install it! and you are done. Castle Windsor is integrated to your very first Asp.Net MVC application.

Lets take a deep look to see what is installed.

My nuget has two dependences on other two packages; Castle.Windsor (which also depends on Castle.Core) and WebActivator. So as expected you can see here the three references:

2011-03-05_2219 

but as I said, my package has only code:

2011-03-05_2221

The bootstraper uses WebActivator to hook in to the application events initialize the container, and run all the installers. Also is responsible to set the ControllerFactory:

[assembly: WebActivator.PreApplicationStartMethod (
    typeof(Bootstrapper), "Wire")]

[assembly: WebActivator.ApplicationShutdownMethod (
    typeof(Bootstrapper), "DeWire")]

namespace SuperShop.App_Start
{
    public static class Bootstrapper
    {
        private static readonly IWindsorContainer container = new WindsorContainer();

        public static void Wire()
        {
            //To be able to inject IEnumerable<T> ICollection<T> IList<T> T[] use this:
            //container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel, true));
            //Documentation http://docs.castleproject.org/Windsor.Resolvers.ashx
            
            //To support typed factories add this:
            //container.AddFacility<TypedFactoryFacility>();
            //Documentation http://docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx
            
            container.Install(FromAssembly.This());
            var controllerFactory = new WindsorControllerFactory(container.Kernel);
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);
        }

        public static void DeWire()
        {
            container.Dispose();
        }
    }
}

The controller factory is (I took this code from Castle wiki):

public class WindsorControllerFactory : DefaultControllerFactory
{
    private readonly IKernel kernel;

    public WindsorControllerFactory(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public override void ReleaseController(IController controller)
    {
        kernel.ReleaseComponent(controller);
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            throw new HttpException(404, 
                string.Format("The controller for path '{0}' could not be found.", 
                requestContext.HttpContext.Request.Path));
        }
        return (IController)kernel.Resolve(controllerType);
    }
}

And the controller installer is:

public class ControllersInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(AllTypes.FromThisAssembly()
                            .BasedOn<IController>()
                            .If(Component.IsInSameNamespaceAs<HomeController>())
                            .If(t => t.Name.EndsWith("Controller"))
                            .Configure(c => c.LifeStyle.Transient));
    }
}

One last thing the package did is to install the handler for the “PerRequest” lifestyle on the web.config (as explained here):

2011-03-05_2233

 

Although the process of creating a nuget package is very well explained in the codeplex site, you mind find useful to look directly at my template, the code is here and it is free for everything.

I hope you find useful this little thing ! :)

| More

In this post I’ll describe a mechanism to manage nhibernate session following the widely known patter “session-per-request”.

Introduction

The session-per-request pattern is very well defined and widely used; as follows

A single Session and a single database transaction implement the processing of a particular request event (for example, a Http request in a web application).

What do we have currently?

The first thing you will notice when talking about nhibernate session management is a little interface inside NHibernate;

public interface ICurrentSessionContext
{
    ISession CurrentSession();
}

The only purpose of the implementors is to store and retrieve the current session from somewhere. This class is used by the SessionFactory of nhibernate when calling the method GetCurrentSession().

There are lot of implementations of ICurrentSessionContext but for web the two more important are:

  • WebSessionContext inside NHibernate (namespace NHibernate.Context)
  • WebSessionContext inside uNhAddIns.Web (namespace Session.Easier)

They are pretty similar but the one inside uNhAddins supports multi-session-factory scenarios.

Where do we init & store the session?

We have an httpmodule in uNhAddins which add handler for the BeginRequest as follows:

Untitleddrawing (2)

The problem

Although the afore mentioned handler does not open a session and a transaction for images or JavaScript files there might be some request to pages that will not talk with the persistence and we don’t want a OpenSession/BeginTransaction there.

Ayende already talked about this in his blog. But the problem is that he only wrote about the Session which is really light to instantiate. The problem is how do we handle the scope of the transaction which is not so light?

Alternative solutions

There are currently three solutions for this problem:

  • Use BeginRequest/EndRequest to open/close the session. Handle the transaction with AOP – attributes. I am not sure but I think this is the case for the AutoTransaction facility of castle.
  • To use Asp.Net MVC ActionFilters to Open/Close the session and the transaction.
  • There is a third which is an antipattern; using implicit transactions for most of the cases and explicit for some others.

The main problem with these approaches is that you need to explicitly put something to say that some piece of code will use a session/transaction. Even if you do it with AOP!

My new solution

My new solution is to store a Lazy<ISession> per request instead of an ISession. Initialize in the first usage and finalize in the EndRequest – only if it was used/opened.

The implementation I’ll show also support multi-session factories.

The ICurrentSessionContext looks as follows:

public class LazySessionContext : ICurrentSessionContext
{
    private readonly ISessionFactoryImplementor factory;
    private const string CurrentSessionContextKey = "NHibernateCurrentSession";

    public LazySessionContext(ISessionFactoryImplementor factory)
    {
        this.factory = factory;
    }

    /// <summary>
    /// Retrieve the current session for the session factory.
    /// </summary>
    /// <returns></returns>
    public ISession CurrentSession()
    {
        Lazy<ISession> initializer;
        var currentSessionFactoryMap = GetCurrentFactoryMap();
        if(currentSessionFactoryMap == null || 
            !currentSessionFactoryMap.TryGetValue(factory, out initializer))
        {
            return null;
        }
        return initializer.Value;
    }

    /// <summary>
    /// Bind a new sessionInitializer to the context of the sessionFactory.
    /// </summary>
    /// <param name="sessionInitializer"></param>
    /// <param name="sessionFactory"></param>
    public static void Bind(Lazy<ISession> sessionInitializer, ISessionFactory sessionFactory)
    {
        var map = GetCurrentFactoryMap();
        map[sessionFactory] = sessionInitializer;
    }

    /// <summary>
    /// Unbind the current session of the session factory.
    /// </summary>
    /// <param name="sessionFactory"></param>
    /// <returns></returns>
    public static ISession UnBind(ISessionFactory sessionFactory)
    {
        var map = GetCurrentFactoryMap();
        var sessionInitializer = map[sessionFactory];
        map[sessionFactory] = null;
        if(sessionInitializer == null || !sessionInitializer.IsValueCreated) return null;
        return sessionInitializer.Value;
    }

    /// <summary>
    /// Provides the CurrentMap of SessionFactories.
    /// If there is no map create/store and return a new one.
    /// </summary>
    /// <returns></returns>
    private static IDictionary<ISessionFactory, Lazy<ISession>> GetCurrentFactoryMap()
    {
        var currentFactoryMap = (IDictionary<ISessionFactory,Lazy<ISession>>)
                                HttpContext.Current.Items[CurrentSessionContextKey];
        if(currentFactoryMap == null)
        {
            currentFactoryMap = new Dictionary<ISessionFactory, Lazy<ISession>>();
            HttpContext.Current.Items[CurrentSessionContextKey] = currentFactoryMap;
        }
        return currentFactoryMap;
    }
}

The new HttpModule is:

public class NHibernateSessionModule : IHttpModule
{
    private HttpApplication app;
    private ISessionFactoryProvider sfp;

    public void Init(HttpApplication context)
    {
        app = context;
        sfp = (ISessionFactoryProvider) 
                  context.Application[SessionFactoryProvider.Key];
        context.BeginRequest += ContextBeginRequest;
        context.EndRequest += ContextEndRequest;
    }

    private void ContextBeginRequest(object sender, EventArgs e)
    {
        foreach (var sf in sfp.GetSessionFactories())
        {
            var localFactory = sf;
            LazySessionContext.Bind(
                new Lazy<ISession>(() => BeginSession(localFactory)), 
                sf);
        }
    }

    private static ISession BeginSession(ISessionFactory sf)
    {
        var session = sf.OpenSession();
        session.BeginTransaction();
        return session;
    }

    private void ContextEndRequest(object sender, EventArgs e)
    {
        foreach (var sf in sfp.GetSessionFactories())
        {
            var session = LazySessionContext.UnBind(sf);
            if (session == null) continue;
            EndSession(session);
        }
    }

    private static void EndSession(ISession session)
    {
        if(session.Transaction != null && session.Transaction.IsActive)
        {
            session.Transaction.Commit();
        }
        session.Dispose();
    }

    public void Dispose()
    {
        app.BeginRequest -= ContextBeginRequest;
        app.EndRequest -= ContextEndRequest;
    }
}

You can see here how we bind to the Lazy to the current context and the initializer. The BeginSession method initializes a session and a transaction.

The UnBind method returns a session only if the Lazy was initialized. If it returns something we properly commit the transaction and dispose the session.

The ISessionFactoryProvider is:

public interface ISessionFactoryProvider
{
    IEnumerable<ISessionFactory> GetSessionFactories();
}

and the SessionFactoryProvider is just an store for the constant:

public class SessionFactoryProvider
{
    public const string Key = "NHibernateSessionFactoryProvider";
}

I didn't write an implementation for ISessionFactoryProvider because I’m using castle typed factories.

The IWindsorInstaller for castle looks as follows:

public class NHibernateInstaller : IWindsorInstaller
{
    #region IWindsorInstaller Members

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component.For<ISessionFactory>()
                               .UsingFactoryMethod(k => BuildSessionFactory()));

        container.Register(Component.For<NHibernateSessionModule>());

        container.Register(Component.For<ISessionFactoryProvider>().AsFactory());
        
        container.Register(Component.For<IEnumerable<ISessionFactory>>()
                                    .UsingFactoryMethod(k => k.ResolveAll<ISessionFactory>()));

        HttpContext.Current.Application[SessionFactoryProvider.Key]
                        = container.Resolve<ISessionFactoryProvider>();
    }

    #endregion

    public ISessionFactory BuildSessionFactory()
    { 
        var config = new Configuration().Configure();
        //your code here :)
        return config.BuildSessionFactory();
    }
}

The only thing you have to do in NHibernate is to tell which is the CurrentSessionContextClass as follows:

configuration.Properties[Environment.CurrentSessionContextClass]
    = typeof (LazySessionContext).AssemblyQualifiedName;

Working with multiples session factories

When working with multiples session factories, the way to go is to name your components in the container:

container.Register(Component.For<ISessionFactory>()
                            .UsingFactoryMethod(...)
                            .Named("MySf1"));

Then you can start naming your Daos and explicitly overriden whenever they are injected:

container.Register(Component.For(typeof(IDao<>))
                            .ImplementedBy(typeof(Dao<>))
                            .ServiceOverrides(ServiceOverrides.ForKey("sessionFactory").Eq(MySf1))
                            .Named("SalesDao"));

container.Register(Component.For(typeof(IMyService<>))
                            .ImplementedBy(typeof(MyService<>))
                            .ServiceOverrides(ServiceOverrides.ForKey("dao").Eq(MyDao1)));

Another way is to have a factory like this one:

public interface IDaoFactory
{
     IDao<T> GetSalesDao();
     IDao<T> GetCMSDao();
}

This will work out of the box with castle typed factories, following the pattern Get[Dao component name]. With other containers you will have to implement the interface.

Remember also that NHibernate lets you name your session factory through the configuration, that is sometimes useful.

How to use the ISession from my code?

The same way I do since long time ago;

public class Dao<T> : IDao<T>
{
    private readonly ISessionFactory sessionFactory;

    public Dao(ISessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }

    public void Save(T transient)
    {
        sessionFactory.GetCurrentSession().Save(transient);
    }

    //Other methods

Injecting the ISessionFactory instead an ISession has the following advantages:

  • It is very handy to use stateless session or a short lived session in some methods for some queries through OpenStatelessSession/OpenSession
  • The lifestyle of the Dao is not tied to the Session.  It could be even singleton.

Other session managements

In unhaddins there are various contexts;

  • PerThread
  • ConversationalPerThread
  • Web

And ways to hook such contexts;

  • In winforms; for use with the pattern Conversation per Business transaction.
  • In WCF; an OperationBehavior
  • In web an httpmodule

It is up to you to choose the combination. For instance when doing WCF that will run inside iis, you can use the operationbehavior + web. But when you do WCF out of IIS, you can use OperationBehavior + PerThread.

The important thing about this is that your DAOs are exactly the same despite the management you use.

Notes

-For non-.Net 4 projects; as Richard Birkby points out you can use the Lazy<T> inside Mono.

Finally

I hope you find this useful.

This code is not going to be in uNhAddins for now. You can copy&paste all the code from this gist.

| More