Showing posts with label Fluent NHibernate. Show all posts
Showing posts with label Fluent NHibernate. Show all posts

Friday, 12 March 2010

Talking Shop

Last week I was featured on the Talking Shop Down Under podcast. Fellow aussie Richard Banks was kind enough to extend me an invitation a few weeks back to join him on his show but I told him there were “… many more interesting aussies to interview before we get to me” and suggested he start with Joe Albahari (LINQPad rocks!!). Boy I knew I was in trouble when the very next podcast rolled through featuring Joe – Richard sure doesn’t waste any time!

In the podcast we discuss Fluent NHibernate, git, and my reasons for doing open source. For those of you that were hoping for some more Reactive Extensions content, I’m afraid I’ve been neglecting Rx lately so I didn’t feel qualified to talk much about it. Maybe next time?

Thanks to Richard for having me on the show, it was lots of fun. If you do have a listen, please feel free to leave a comment – this was my first podcast and I haven’t done a great deal of public speaking so I could benefit from some constructive criticism. Cheers!

Wednesday, 29 April 2009

A Fluent NHibernate update

Since James has announced the latest happenings in the ongoing saga of moving Fluent NHibernate to using a semantic model, I thought a companion post might be appropriate.

My first post on the Fluent NHibernate rewrite is as good a place to start as any. In it I explained the limitations of the existing implementation and outlined my strategy for dissolving those limitations. My branch differs from the trunk by separating the fluent interface from the mapping model. The fluent interface manipulates the underlying model, and a family of visitors build a Hbm object graph that represents that underlying model. That object graph is serialized to xml and then passed to NHibernate. This graph consists of classes that are generated from the NHibernate mapping schema, so the serialization step is all automatic and works flawlessly.

The use of the visitor pattern allows for two things. One, the mapping model is not tied to any particular output format. Sure we pass NHibernate xml today, but tomorrow it would be nice to pass it the Hbm object graph directly so it can skip the xml schema validation step. The day after it would be nice to pass it a prebuilt NHibernate.Mapping graph, which is an idea that Tuna Toksoz was exploring from within my branch. Secondly, the visitor implementation allowed for powerful manipulations of the mapping model that would otherwise be difficult. I talked more about the visitor implementation here.

Sure, passing NHibernate its mappings in a format other than xml would be nice some day, but there was another reason why I chose to use a Hbm graph instead of directly writing xml. Basically, its much harder to go off the rails when working with the Hbm objects. One example is that the NHibernate schema is finicky about element ordering and you simply don’t have to worry about this when working with Hbm objects.

As time went on the code base grew, things changed, but slow and steady progress was made. The problem is that slow and steady doesn’t always win the race – specifically in the case where the goalpost is moving as fast or faster than you! This is the classic rewrite problem. I’m sure you are familiar with it – its why all the well respected software professionals tell you that rewriting your app is a fools errand. And don’t get me wrong, I am in agreement here. I approached my work to rewrite Fluent NHibernate as a prototyping exercise - “one possible future” if you will. As the work continued I would discuss our long term goals with James and for a while we found ourselves hoping that we could replace the existing trunk with my branch, if only we could “catch up” to the trunk functionality. Of course this sort of thinking was dangerous, and the consequences are well described in James’s post. My intentions, while good, have lead to a lack of progress on the Fluent NHibernate trunk and this is simply not a healthy place to be.

James asked me whether I could see a way to merge the two code bases. Basically inject my model into the existing guts of the trunk. I told him I couldn’t see a way how, but I encouraged him to try. The problem, I’m sure you’ve already guessed, is that I was too “caught up” in my code and simply not prepared to make sacrifices. This is why James managed something that I could not – he merged my branch into the trunk code under an “integration”  branch, with all the existing trunk tests passing. Its not pretty, but I suspect that it represents the best direction to work from. We can now do what the experts tell us to do and refactor, rather than rewrite.

So what were the sacrifices? The main one is the Hbm object graph approach. Fluent NHibernate will only be capable of spitting out xml for the near future. Lets face it, its not a huge loss. Plus I say near future because the visitor implementation survived, so there is no reason why we couldn’t later start retrofitting my Hbm code in. I am yet to take full stock of the “casualties”, but I expect that everything that has been lost in the merge can be regained through a gradual process of refactoring and reintroducing code and ideas from my branch. It will be fun!

Finally I want to use this post as an opportunity to thank James for all his amazingly hard work on this great project. We don’t always see eye to eye but the thing that I often remind myself is that time and again he has proven to me that he has his finger on the pulse of our users and can see how this project can best fulfil their needs. Please keep it up James.

Monday, 9 March 2009

Supporting multiple NHibernate versions in Fluent NHibernate semantic model

My Fluent NHibernate semantic model rewrite is designed to support multiple versions of NHibernate simultaneously. At the moment, I support NH 2.0.1GA and 2.1.0.1001 (this was a trunk snapshot). My goal is to support the latest official release and to keep as up to date with the trunk as possible; time will tell how well this pans out.

The semantic model rewrite makes heavy use of classes that are generated from the NH mapping schema. These classes are all prefixed with Hbm, so I am in the habit of calling them “Hbm*” classes. Here is some example code that builds a HbmKey representation of a KeyMapping:

public override void ProcessKey(KeyMapping keyMapping)
{
    _hbm = new HbmKey();

    if (keyMapping.Attributes.IsSpecified(x => x.Column))
        _hbm.column1 = keyMapping.Column;

    if (keyMapping.Attributes.IsSpecified(x => x.ForeignKey))
        _hbm.foreignkey = keyMapping.ForeignKey;

    if (keyMapping.Attributes.IsSpecified(x => x.PropertyReference))
        _hbm.propertyref = keyMapping.PropertyReference;

    if (keyMapping.Attributes.IsSpecified(x => x.CascadeOnDelete))
        _hbm.SetCascadeOnDelete(keyMapping.CascadeOnDelete);
}

Because the NH mapping schema changes from version to version, the public interface for these classes also changes from version to version. See that “column1” property? Its entirely possible it was called “column” in an earlier version of NH. Obviously, if it were to change back to “column” tomorrow, this code would no longer compile. Given this, how can Fluent NH hope to simultaneously support multiple NH versions? The answer is to put any version specific code in a separate assembly.

Today I will fix a NH2.1 incompatibility that I introduced a few days ago when adding the ability to specify the column name for a property. Here is the code I wrote while working against NH2.0.1:

public override void ProcessProperty(PropertyMapping propertyMapping)
{
    _hbm = new HbmProperty();
    _hbm.name = propertyMapping.Name;

    if(propertyMapping.Attributes.IsSpecified(x => x.IsNotNullable))
        _hbm.SetNotNull(propertyMapping.IsNotNullable);

    if (propertyMapping.Attributes.IsSpecified(x => x.Length))
        _hbm.length = propertyMapping.Length.ToString();

    if (propertyMapping.Attributes.IsSpecified(x => x.ColumnName))
        _hbm.column1 = propertyMapping.ColumnName;
}

The very last line is the one to watch here. You can see its setting the “column1” property. This worked fine against NH2.0.1 but when I ran my rake script to switch over to NH2.1 today, this code no longer compiled - the property is now called “column”. As I mentioned above, my strategy for dealing with this problem is to use version specific assemblies. Here is the Fluent NH solution:

image

The two “Versioning” projects are where the version specific code goes – they each reference their own version of NHibernate. Each project contains the same set of extensions methods, each method implemented slightly differently depending on the versioning requirements. The two projects share the same namespace and output an assembly with the same name (FluentNHibernate.Versioning) and to the same location. Neither project is included in the default build configuration, so they have to be built explicitly. The act of building one of these versioning projects will make it “active” because the assembly is output to the same location that the FluentNHibernate project is referencing.

With the background out of the way, lets fix the problem with with “column1” property on HbmProperty. First I open the Versioning.NH20 project, find the HbmPropertyExtensions and add an extension method:

public static class HbmPropertyExtensions
{
    ...
public static void SetColumn(this HbmProperty hbmProperty, string column) { hbmProperty.column1 = column; } }

I then modify the code to call the extension method:

if (propertyMapping.Attributes.IsSpecified(x => x.ColumnName))
    _hbm.SetColumn(propertyMapping.ColumnName);

I compile the Versioning.NH20 project to make sure its active and run my tests. I already have a test that is verifying this implementation – here it is:

[Test]
public void Should_write_the_attributes()
{
    var testHelper = new HbmTestHelper<PropertyMapping>();
    testHelper.Check(x => x.Name, "test").MapsToAttribute("name");
    testHelper.Check(x => x.Length, 50).MapsToAttribute("length");
    testHelper.Check(x => x.IsNotNullable, true).MapsToAttribute("not-null");
    testHelper.Check(x => x.ColumnName, "thecolumn").MapsToAttribute("column"); <--- HERE
    var writer = new HbmPropertyWriter();
    testHelper.VerifyAll(writer);
}

Because this test verifies that a certain property is written to the correct xml attribute, it works for both versions of NH. Regardless of what the property is called on the Hbm class, its written to the “column” attribute.

The tests all pass, so I switch to NH2.1 using my rake script and move to the Versioning.NH21 project. Again, I add an extension method:

public static class HbmPropertyExtensions
{
    ...
public static void SetColumn(this HbmProperty hbmProperty, string column) { hbmProperty.column = column; } }

This looks almost the same as the code above, but notice that the “1” is gone. I compile the Versioning.NH21 project to make sure its active and run the tests. They all pass!

So far, all the versioning issues I’ve ran into were easily fixed like the one above. Lets hope they are all this simple!

 

Saturday, 21 February 2009

Fluent NHibernate semantic model: Visitors

My work-in-progress semantic model based version of Fluent NHibernate makes heavy use of the visitor pattern. Currently, the visitor implementation is there to serve two purposes:

  1. Facilitate the construction of a Hbm* representation of the mapping model. Hbm* refers to the set of classes found in the NHibernate.Cfg.MappingSchema namespace that are generated from the NHibernate mapping schema. My version of Fluent NHibernate communicates with NHibernate by serializing the Hbm* representation to xml.
  2. Enable powerful, user-defined conventions that walk the mapping model and make changes. The NamingConvention class is a very simple example of this – it takes mapping model instances and sets their Name property based on reflected data such as the System.Type or the PropertyInfo.

Lets begin by looking at the implementation of AcceptVisitor for the root of the mapping model – HibernateMapping:

public override void AcceptVisitor(IMappingModelVisitor visitor)
{
    visitor.ProcessHibernateMapping(this);

    foreach (var classMapping in Classes)
        visitor.Visit(classMapping);
}

This is reasonably straightforward. The HibernateMapping tells the visitor to first process a HibernateMapping instance, and passes itself as the argument. Then it tells the visitor to visit each of the child classes. What the visitor does when its told to visit a ClassMapping is its business, but what it is likely to do is call AcceptVisitor on the ClassMapping:

public override void AcceptVisitor(IMappingModelVisitor visitor)
{
    visitor.ProcessClass(this);            

    if (Id != null)
        visitor.Visit(Id);

    if (Discriminator != null)
        visitor.Visit(Discriminator);

    foreach (var subclass in Subclasses)
        visitor.Visit(subclass);

    base.AcceptVisitor(visitor);
}

This is similar to the previous AcceptVisitor implementation, but its worth noting that at the end, it calls base.AcceptVisitor(visitor). This is necessary because ClassMapping inherits from a common base class (JoinedSubclassMapping and SubclassMapping also inherit from this base class). Here is AcceptVisitor on ClassMappingBase:

public override void AcceptVisitor(IMappingModelVisitor visitor)
{
    foreach (var collection in Collections)
        visitor.Visit(collection);

    foreach (var property in Properties)
        visitor.Visit(property);

    foreach (var reference in References)
        visitor.Visit(reference);
}

Of course – all class mappings, regardless of how they fit into an inheritance hierarchy, can have collections, properties and references (many-to-ones). Its probably not necessary to follow this any further. The important point is that as long as the visitor calls AcceptVisitor when it is told to visit something, then it will make its way along the entire mapping model. To make life easier, I’ve implemented a DefaultMappingModelVisitor class that does precisely this. It has a whole bunch of code that all looks very similar to this:

public override void Visit(PropertyMapping propertyMapping)
{
    propertyMapping.AcceptVisitor(this);
}

public override void Visit(ManyToOneMapping manyToOneMapping)
{
    manyToOneMapping.AcceptVisitor(this);
}

public override void Visit(KeyMapping keyMapping)
{
    keyMapping.AcceptVisitor(this);
}
.. Many more Visit methods

Now you might be looking at this and wondering why this is necessary. Why can’t we skip this completely, and just have AcceptVisitor implementations that will call AcceptVisitor directly like this:

public override void AcceptVisitor(IMappingModelVisitor visitor)
{
    visitor.ProcessHibernateMapping(this);

    foreach (var classMapping in Classes)
        classMapping.AcceptVisitor(visitor); <--- JUST DO THIS??
}

The answer is that the proposed change will work when you want one single visitor instance to visit the entire mapping model. While this works fine for conventions (as you will see in a moment), it does not work so well for building the Hbm representation. I’ll get to that in a second, but lets first take a look at the simpler case of the conventions. Here is a gutted version of the NamingConvention:

public class NamingConvention : DefaultMappingModelVisitor
{
    public Func<MemberInfo, string> DetermineNameFromMember = info => info.Name;
    public Func<Type, string> DetermineNameFromType = type => type.AssemblyQualifiedName;

    public override void ProcessOneToMany(OneToManyMapping oneToManyMapping)
    {
        if (!oneToManyMapping.Attributes.IsSpecified(x => x.ClassName))
        {
            if (oneToManyMapping.ChildType == null)
                throw new ConventionException("Cannot apply the naming convention. No type specified.", oneToManyMapping);
            oneToManyMapping.ClassName = DetermineNameFromType(oneToManyMapping.ChildType);
        }
    }
}

I’ve removed the majority of its implementation for the sake of brevity. As it currently stands, it will walk the entire mapping model (because it inherits from the aforementioned DefaultMappingModelVisitor), and when it encounters a OneToManyMapping, it will attempt to set its ClassName based on the ChildType property. Its worth noting that the full implementation of the NamingConvention class actually handles naming of many other mappings types, such as ClassMappings, ManyToManyMappings, etc. This means that this visitor completely handles the concern of setting the name of mapping model elements for the entire mapping model. This point is important, because the next example is different.  As I mentioned before, this visitor implementation would work fine with the previous simplification of having AcceptVisitor directly call AcceptVisitor on the children. Lets now move on to the process of building a Hbm* representation, and examine why the simplification won’t work so well for this case.

I define an interface for classes that build Hbm:

public interface IHbmWriter<T>
{
    object Write(T mappingModel);        
}    

Here is an example implementor, a hbm writer that will handle ColumnMappings:

public class HbmColumnWriter : NullMappingModelVisitor, IHbmWriter<ColumnMapping>
{
    private HbmColumn _hbm;

    public object Write(ColumnMapping mappingModel)
    {
        _hbm = null;
        mappingModel.AcceptVisitor(this);
        return _hbm;
    }

    public override void ProcessColumn(ColumnMapping columnMapping)
    {
        _hbm = new HbmColumn();
        _hbm.name = columnMapping.Name;
        
        if(columnMapping.Attributes.IsSpecified(x => x.IsNotNullable))
        {
            _hbm.notnull = columnMapping.IsNotNullable;
            _hbm.notnullSpecified = true;
        }

        if (columnMapping.Attributes.IsSpecified(x => x.Length))
            _hbm.length = columnMapping.Length.ToString();
        
//etc
    }
}

You’ll notice that this class inherits from NullMappingModelVisitor, which is basically a blank implementation of IMappingModelVisitor. It has all the methods, but none of them do anything. So this visitor ONLY knows how to handle ColumnMappings - if its passed to any other type of mapping, it will do nothing. This is certainly a difference approach to the NamingConvention, which actually knew how to set the name for Classes, OneToMany’s, ManyToMany’s and many other mapping model elements. So why does this difference exist? Basically, the job of generating all the Hbm that NHibernate requires is too big for one class. Creating separate classes for generating the appropriate HBM helps make the job more manageable. These classes can then be composed, like so:

public class HbmIdWriter : NullMappingModelVisitor, IHbmWriter<IdMapping>
{
    private readonly IHbmWriter<ColumnMapping> _columnWriter;
    private readonly IHbmWriter<IdGeneratorMapping> _generatorWriter;

    private HbmId _hbm;

    public HbmIdWriter(IHbmWriter<ColumnMapping> columnWriter, IHbmWriter<IdGeneratorMapping> generatorWriter)
    {
        _columnWriter = columnWriter;
        _generatorWriter = generatorWriter;
    }

    public object Write(IdMapping mappingModel)
    {
        _hbm = null; 
        mappingModel.AcceptVisitor(this);
        return _hbm;
    }

    public override void ProcessId(IdMapping idMapping)
    {
        _hbm = new HbmId();

        if(idMapping.Attributes.IsSpecified(x => x.Name))
            _hbm.name = idMapping.Name;
    }

    public override void Visit(ColumnMapping columnMapping)
    {
        var columnHbm = (HbmColumn) _columnWriter.Write(columnMapping);
        columnHbm.AddTo(ref _hbm.column);
    }

    public override void Visit(IdGeneratorMapping generatorMapping)
    {
        var generatorHbm = (HbmGenerator) _generatorWriter.Write(generatorMapping);
        _hbm.generator = generatorHbm;
    }
}

This hbm writer handles IdMappings. IdMappings include one or more columns and a generator, so this writer composes a IHbmWriter<ColumnMapping> and a IHbmWriter<IdGeneratorMapping>. In this way, the task of creating the hbm representation can be managed by a family of visitors that delegate to each other as required.

Finally now, I can return to the previous point of why all the AcceptVisitor implementations call visitor.Visit(child) rather than child.AcceptVisitor(visitor). The former allows the current visitor to see that a different visitor is passed in when calling child.AcceptVisitor(). You can see some of this happening above, in the override for Visit(ColumnMapping) – it asks the IHbmWriter<ColumnMapping> to write the column. The implementation of that method will call columnMapping.AcceptVisitor(this). Thus, the Fluent NHibernate semantic model has an implementation of the visitor pattern that supports both single visitors that visit the entire graph themselves, and families of visitors that collaborate to get a large job done.

Sunday, 8 February 2009

Fluent NHibernate semantic model: AttributeStore<T>

My work to rewrite Fluent NHibernate using a semantic model continues at a reasonable pace. I will admit there is some unconventional stuff in the code base, and much of it deserves explanation. Today I would like to explain AttributeStore<T> - what it is for and how it works. Lets start by taking a look at the model class for the contents of a collection with OneToMany semantics:

public class OneToManyMapping : MappingBase, ICollectionContentsMapping
{
    private readonly AttributeStore<OneToManyMapping> _attributes;

    public OneToManyMapping()
    {
        _attributes = new AttributeStore<OneToManyMapping>();
        _attributes.SetDefault(x => x.ExceptionOnNotFound, true);
    }

    public AttributeStore<OneToManyMapping> Attributes
    {
        get { return _attributes; }
    }

    public string ClassName
    {
        get { return _attributes.Get(x => x.ClassName); }
        set { _attributes.Set(x => x.ClassName, value); }
    }

    public bool ExceptionOnNotFound
    {
        get { return _attributes.Get(x => x.ExceptionOnNotFound); }
        set { _attributes.Set(x => x.ExceptionOnNotFound, value); }
    }
}

As you can see, I am doing something unusual in some of the getters and setters. Basically, I am storing the values of certain properties in a dictionary, and these values are keyed on the name of the property you use to access them. Its very easy to add new attributes, I use this Resharper live template:

public $ReturnType$ $PropertyName$
{
    get { return $_attributes$.Get(x => x.$PropertyName$); }
    set { $_attributes$.Set(x => x.$PropertyName$, value); }
}

This approach allows me to write code that asks questions about properties beyond simply “what is the value?”. Here is an example from the NamingConvention class:

public override void ProcessOneToMany(OneToManyMapping oneToManyMapping)
{
    if (!oneToManyMapping.Attributes.IsSpecified(x => x.ClassName))
    {
        if (oneToManyMapping.ChildType == null)
            throw new ConventionException("Cannot apply the naming convention. No type specified.", oneToManyMapping);
        oneToManyMapping.ClassName = DetermineNameFromType(oneToManyMapping.ChildType);
    }
}
This convention walks the mapping model, naming mappings based on the assigned Type or MemberInfo. In this example, if the ClassName property for the OneToManyMapping hasn’t been specified explicitly, then the NamingConvention uses the ChildType property to set the ClassName. If the user has set the ClassName themselves, then I don’t want the NamingConvention to overwrite that, so I ask the question “Is the ClassName property specified?”. If the ClassName property was just implemented as an autoproperty, I would probably have to check if it was null. But what if the property was a bool? Make it a nullable bool? Then I would have nasty if(blah.HasValue) code in various places. Yuck!

Here is another example, this time from the class that creates a HbmOneToMany instance based on my OneToManyMapping:

public override void ProcessOneToMany(OneToManyMapping oneToManyMapping)
{
    _hbmOneToMany = new HbmOneToMany();
    _hbmOneToMany.@class = oneToManyMapping.ClassName;

    if(oneToManyMapping.Attributes.IsSpecified(x => x.ExceptionOnNotFound))
    {
        _hbmOneToMany.SetNotFound(oneToManyMapping.ExceptionOnNotFound);
    }
}

This code always sets the @class field on the HbmOneToMany, but it won’t always call SetNotFound. It only calls SetNotFound if the the ExceptionOnNotFound property was specified. The point of this behaviour is to only generate the xml the user desires. It is not mandatory to set the not-found attribute on a one-to-many element, so why write it if the user hasn’t specified it?

As well as being able to ask questions about the properties, I also wanted a convenient way to copy them. The next code sample is the code for OneToManyPart. This class is part of the fluent interface for FluentNHibernate. It builds up information on the collection being mapped, and builds the appropriate collection when ResolveCollectionMapping() is called (obviously the IsInverse property is the only value copied at the moment, but that will change as the supported functionality grows):

public class OneToManyPart<PARENT, CHILD> : IDeferredCollectionMapping
{
    private readonly PropertyInfo _info;
    private readonly AttributeStore<ICollectionMapping> _attributes;

    private Func<ICollectionMapping> _collectionBuilder;

    public OneToManyPart(PropertyInfo info)
    {
        _info = info;
        _attributes = new AttributeStore<ICollectionMapping>();
        AsBag();   
    }

    public OneToManyPart<PARENT, CHILD> AsBag()
    {
        _collectionBuilder = () => new BagMapping();
        return this;
    }

    public OneToManyPart<PARENT, CHILD> AsSet()
    {
        _collectionBuilder = () => new SetMapping();
        return this;
    }

    public OneToManyPart<PARENT, CHILD> IsInverse()
    {
        _attributes.Set(x => x.IsInverse, true);
        return this;
    }

    ICollectionMapping IDeferredCollectionMapping.ResolveCollectionMapping()
    {
        var collection = _collectionBuilder();       
        _attributes.CopyTo(collection.Attributes);

        collection.PropertyInfo = _info;            
        collection.Key = new KeyMapping();
        collection.Contents = new OneToManyMapping {ChildType = typeof (CHILD)};

        return collection;
    }

}

The relevant lines are at the beginning of ResolveCollectionMapping(). Once the collection instance is created, the attributes collected in the _attributes field are copied to the AttributeStore for the new collection instance.

Well that is probably enough examples of why I am using this pattern. Now I want to run through the implementation. Lets start with AttributeStore<T>:

public class AttributeStore<T>
{
    private readonly AttributeStore _store;

    public AttributeStore()
        : this(new AttributeStore())
    {

    }

    public AttributeStore(AttributeStore store)
    {
        _store = store;
    }

    public U Get<U>(Expression<Func<T, U>> exp)
    {
        return (U)(_store[GetKey(exp)] ?? default(U));
    }

    public void Set<U>(Expression<Func<T, U>> exp, U value)
    {
        _store[GetKey(exp)] = value;
    }

    public void SetDefault<U>(Expression<Func<T, U>> exp, U value)
    {
        _store.SetDefault(GetKey(exp), value);
    }   

    public bool IsSpecified<U>(Expression<Func<T, U>> exp)
    {
        return _store.IsSpecified(GetKey(exp));
    }

    public void CopyTo(AttributeStore<T> target)
    {
        _store.CopyTo(target._store);
    }

    private string GetKey<U>(Expression<Func<T, U>> exp)
    {
        PropertyInfo info = ReflectionHelper.GetProperty(exp);
        return info.Name;
    }
}

As you can see, AttributeStore<T> is a generic wrapper for a non-generic class called AttributeStore. The purpose of AttributeStore<T> is to expose get and set methods that take a lambda, and convert that lambda into a dictionary key, and then delegate to an inner attribute store using that dictionary key. Finally, here is the code for the non-generic attribute store:

public class AttributeStore
{
    private readonly IDictionary<string, object> _attributes;
    private readonly IDictionary<string, object> _defaults;

    public AttributeStore()
    {
        _attributes = new Dictionary<string, object>();
        _defaults = new Dictionary<string, object>();
    }

    public object this[string key]
    {
        get
        {
            if (_attributes.ContainsKey(key))
                return _attributes[key];
            
            if (_defaults.ContainsKey(key))
                return _defaults[key];

            return null;
        }
        set { _attributes[key] = value; }
    }

    public bool IsSpecified(string key)
    {
        return _attributes.ContainsKey(key);
    }

    public void CopyTo(AttributeStore store)
    {
        foreach (KeyValuePair<string, object> pair in _attributes)
            store._attributes[pair.Key] = pair.Value;
    }

    public void SetDefault(string key, object value)
    {
        _defaults[key] = value;
    }
}

AttributeStore is just a wrapper for a couple of dictionaries, one for the values that have been specified, and one for the default values. That’s pretty much all there is to it.

I see AttributeStore<T> as a superior alternative to the weakly typed bag of attributes approach that Fluent NHibernate currently uses.There are no magic strings, and its all strongly typed. Its more powerful than just using properties with backing fields, and it requires pretty much the same amount of code. Sure, its much slower, but performance is not really a concern for Fluent NHibernate. I can see myself using this pattern on other projects.

Tuesday, 9 December 2008

A Fluent NHibernate rewrite

A little less than 6 months ago I joined the Fluent NHibernate open source project. More recently I’ve struggled with fielding feature requests and partial patches, and I believe that the source of my difficulty has been the structure of the Fluent NHibernate codebase. In my opinion, the fundamental problem with the code is a lack of separation of concerns. Lets take a look at some excerpts from the ClassMap class:

public virtual IdentityPart Id(Expression<Func<T, object>> expression, string column)
{
    PropertyInfo property = ReflectionHelper.GetProperty(expression);
    var id = column == null ? new IdentityPart(property) : new IdentityPart(property, column);
    AddPart(id);
    return id;
}
This Id method is part of the fluent interface. You can see it takes an expression and does some reflection to convert that expression into a format that can be used to configure NHibernate.
public XmlDocument CreateMapping(IMappingVisitor visitor)
{
    if (String.IsNullOrEmpty(TableName))
        TableName = visitor.Conventions.GetTableName.Invoke(typeof(T));

    visitor.CurrentType = typeof(T);
    XmlDocument document = getBaseDocument();
    setHeaderValues(visitor, document);

    foreach (var import in imports)
    {
        import.Write(document.DocumentElement, visitor);
    }

    XmlElement classElement = createClassValues(document, document.DocumentElement);
    writeTheParts(classElement, visitor);

    return document;
}

This CreateMapping method generates the eventual output that will be fed to NHibernate: an XmlDocument.

The fact that these two methods exist in the same class is a prime example of why I have found the code base increasingly difficult to work with. There is no seperation between the function of specifying the mapping (by calling into the fluent interface) and generating the mapping (writing an xml document). It becomes difficult to reason about the capability of the library as the public interface consists of a big pile of lambda goo. Thinking more ambitiously, if you wanted to develop an alternative fluent api while continuing to utilize all the existing infrastructure provided by Fluent NHibernate, you would find it very difficult indeed.

So, what to do? Hell, if your a programmer you shouldn’t have to ask that question! The same thing we always want to do when the old code base starts to feel clunky. Throw it all out and start from scratch! Ok, rarely is this actually a good idea but that is the nice thing about doing open source on your own time – you can do whatever the hell you want.

Well what should the code base actually look like? Chad Myers had the answer, so I rolled up my sleeves and went to work. That was a couple of weeks ago. Today I hit a milestone - I was able to successfully configure NHibernate for a simple 3 entity scenario, using an API that looks just like the existing Fluent NHibernate API but actually utilizes a model that constructs an object graph of Hbm* instances (these are classes provided by NHibernate that are generated from the mapping schema) and then serializes that graph to xml. Hitting this milestone meant that it was time to share my work, so I committed my version as a branch. I included a decent chunk of notes in the commit message and don’t intend to repeat them all here, so I recommend you review the log if you would like to know more.

So what does this rewrite actually look like?

First of all, here is the tiny demonstration domain that I have been using so far:

 image

Now here is the fluent mapping that I managed to get working today:

private class ArtistMap : ClassMap<Artist>
{
    public ArtistMap()
    {
        Id(x => x.ID);
        Map(x => x.Name)
            .WithLengthOf(50)
            .CanNotBeNull();
        HasMany<Album>(x => x.Albums)
            .AsSet()
            .IsInverse();
    }
}

private class AlbumMap : ClassMap<Album>
{
    public AlbumMap()
    {
        Id(x => x.ID);
        Map(x => x.Title)
            .WithLengthOf(50)
            .CanNotBeNull();
        References(x => x.Artist);
        HasMany<Track>(x => x.Tracks)
            .AsSet()
            .IsInverse();
    }
}

private class TrackMap : ClassMap<Track>
{
    public TrackMap()
    {
        Id(x => x.ID);
        Map(x => x.Name)
            .WithLengthOf(50)
            .CanNotBeNull();
        Map(x => x.TrackNumber);
        References(x => x.Album)
            .CanNotBeNull();
    }
}

Look familiar? It should if you are a Fluent NHibernate user or developer! To demonstrate the flexibility of the rewrite, I implemented a very small subset of the existing fluent interface. That implementation was put in a completely separate assembly, to demonstrate that the core of Fluent NHibernate is not tied to any specific fluent api. If you wanted to, you could map a class unfluently, using the core model like so: (this example only maps Album)

var root = new HibernateMapping();

var classMapping = new ClassMapping
   {
       Name = typeof (Album).AssemblyQualifiedName,
       Id = new IdMapping("ID", new IdColumnMapping("ID"), IdGeneratorMapping.NativeGenerator)
   };
root.AddClass(classMapping);

var titleMapping = new PropertyMapping("Title") {Length = 50, AllowNull = false};
classMapping.AddProperty(titleMapping);

var artistMapping = new ManyToOneMapping("Artist");
classMapping.AddReference(artistMapping);

var trackMapping = new SetMapping
   {
       Name = "Tracks",
       Key = new KeyMapping(),
       Contents = new OneToManyMapping(typeof (Track).AssemblyQualifiedName)
   };
classMapping.AddCollection(trackMapping);

You could then serialize the underlying Hbm graph and this is the result:

image

But of course, doing it that way sucks. This project is called Fluent NHibernate after all!  You don’t even have any strong typing on the properties! I can’t see anyone using the core model directly. Its designed to be a base for fluent api’s to build on.

The core model is still in a rough state. At the moment it has very little functionality other than to wrap the Hbm* classes. However I expect this will change. One of the many issues that need addressing is that of support for conventions – I expect the conventions implementation will require the model to be richer, to accept Type and PropertyInfo instances rather than awful strings. But don’t worry! It won’t get too rich – you won’t see any Expression<Func<T, Object>> hanging off the model – that stuff belongs in the fluent interface.

I am really quite excited about how the seperation between the mapping model and the fluent interface could be leveraged. The DDD fanboi in me would love to see a fluent interface that allows you to describe your aggregate structure in addition to mapping to NHibernate.

Thursday, 21 August 2008

A less fragile way to invoke a generic method with a dynamic type argument

A fellow Fluent NHibernate contributor Andrew Stewart called out for ideas on how some of his code could be refactored and if you've programmed with me you will know that I jumped at the chance. Here is the rather unfortunate code:

var findAutoMapMethod = typeof(AutoMapper).GetMethod("MergeMap");
var genericfindAutoMapMethod = findAutoMapMethod.MakeGenericMethod(type);
genericfindAutoMapMethod.Invoke(autoMap, new[] { mapping });

Here is what Andrew wants to do (sort of):

Type type = GetSomeType();
autoMap.MergeMap<type>(mapping);

This is illegal because you can't pass a type instance as a type parameter to a generic method. For example, you can't declare a list of strings like this:

List<typeof(string)> stringList;

Andrew is calling a generic method but he doesn't know the type argument at compile time. The only way around this is reflection, and we all know that reflection is fragile - if someone changes the MergeMap method to be called MergeMapping, the code will compile and fail at runtime (hopefully when your unit tests are executed!). Fortunately, there is a way to make this block of code significantly less fragile. To do this, I'm going to rely on the handy ReflectionHelper that is part of the Fluent NHibernate code base. Here's the method I'm going to use

public static MethodInfo GetMethod(Expression<Func<object>> expression)
{
 MethodCallExpression methodCall = (MethodCallExpression)expression.Body;
 return methodCall.Method;
}

So if I pass this baby a lambda expression containing a method invocation, it gives me the corresponding MethodInfo. Sweet! Lets use it

var templateMethod = ReflectionHelper.GetMethod((AutoMapper a) => a.MergeMap<object>(null));

Notice the type argument of 'object' ? Its a placeholder. The parameter 'null' is also a placeholder. What you need to realise is that we are not going to -execute- the code in that lambda. The reflection helper is going to inspect it and give us a MethodInfo to work with. Before we can invoke the MethodInfo, we need to replace the first placeholder, which is why I have called this one templateMethodInfo. Lets replace the placeholder:

var realMethodInfo = templateMethod.GetGenericMethodDefinition()
                     .MakeGenericMethod(type);

The GetGenericMethodDefinition call lets you obtain a MethodInfo for an unbound version of MergeMap. Once the method is unbound, we supply the particular type argument we want, being 'type' in this case. MakeGenericMethod takes an array of types so this process would also work fine for a generic method that has more than one type argument. To further illustrate this process, here is another example:

public static void DoSomething<T, U>() { }
...
static void Main(string[] args)
{
 Action doSomethingAction = DoSomething<object, object>;
 MethodInfo info = doSomethingAction.Method;
 Console.WriteLine(info);
 info = info.GetGenericMethodDefinition();
 Console.WriteLine(info);
 info = info.MakeGenericMethod(typeof(string), typeof(int));
 Console.WriteLine(info);
 Console.ReadLine();
}

OUTPUT: Void DoSomething[Object,Object]() Void DoSomething[T,U]() Void DoSomething[String,Int32]()

Getting back to the task at hand, we can now invoke realMethodInfo, but we must be sure to pass the original intended argument 'mapping':

realMethodInfo.Invoke(autoMap, new[] { mapping });

And thats it! Now if MergeMap is renamed, the lambda body will be updated accordingly by the refactoring tools. Now this code is still fragile because if another type argument is added to MergeMap, this code won't fail until runtime. Lets specifically check for this case and throw an appropriate exception. Lets also wrap it all up in one nice convienent method:

public static class InvocationHelper
{
 public static object InvokeGenericMethodWithDynamicTypeArguments<T>(T target, Expression<Func<T, object>> expression, object[] methodArguments, params Type[] typeArguments)
 {
     var methodInfo = ReflectionHelper.GetMethod(expression);
     if (methodInfo.GetGenericArguments().Length != typeArguments.Length)
         throw new ArgumentException(
             string.Format("The method '{0}' has {1} type argument(s) but {2} type argument(s) were passed. The amounts must be equal.",
             methodInfo.Name,
             methodInfo.GetGenericArguments().Length,
             typeArguments.Length));

     return methodInfo
         .GetGenericMethodDefinition()
         .MakeGenericMethod(typeArguments)
         .Invoke(target, methodArguments);
 }
}

And call it:

InvocationHelper.InvokeGenericMethodWithDynamicTypeArguments(
             autoMap, a => a.MergeMap<object>(null), new[] { mapping }, type);

Ok so its certainly not as clear or robust as:

autoMap.MergeMap<type>(mapping);

But the former has the advantage of actually COMPILING, while the latter does not.

My first open source project

A few weeks ago, I joined an open source project that was just starting up. Its called Fluent NHibernate and provides an alternative to XML based or attribute based mapping of NHibernate domain objects. The project owner James Gregory does a much better job of explaining it than I could.

Why am I only mentioning it now? Well during the first week I was too busy trying to get up to speed and make a useful commit to blog about it. As for the last couple of weeks, I've been holidaying in France and Italy and its been hard enough just keeping up with my RSS and mailing lists.

It has been a great experience so far. The other contributors are really friendly and smart, and I am impressed by the sheer volume (and quality) of work being performed. I'm learning how to use Subversion and really missing continuous integration (yes I already broke the build, managed it on my 2nd commit).

Incidentally, this is my first post using Windows Live Writer. It seems nicer than the Blogger web interface.