Friday, May 15, 2009

FluentNHibernate Mappings: Any

Recently Oren (Ayende) had a serious of posts on NHibernate mappings and the various options you can configure using Xml mappings. This series of posts takes those examples and shows how you can use FluentNHibernate to configure the same mappings.

This is a companion post for Oren’s post on the <any> mapping in NHibernate, here. I recommend reading his post before venturing forward.

In Fluent NHibernate you can use the ReferencesAny mapping method to output a <any> mapping:

ReferencesAny(mapping => mapping.Payment)

    .EntityTypeColumn("PaymentType")

    .EntityIdentifierColumn("PaymentId")

    .AddMetaValue<CreditCardPayment>("Credit")

    .AddMetaValue<CheckPayment>("Check")

    .IdentityType(identity => typeof(int));

Note: This mapping method at this time is generating the <any> mapping incorrectly. The mapping that is being generated contains <any> before the <Id> element causing NHibernate to complain. I've submitted a patch to fix this behavior, which you can get from here: http://code.google.com/p/fluent-nhibernate/issues/detail?id=228

Note2: ReferencesAny is available in the latest trunk as support for it was added fairly recently. So if you can't seem to find it in the fluent-nhibernate.dll build you are using, get latest from trunk and build it.

The ReferencesAny prety much matches the <any> element. You specify the meta values using the AddMetaValue method, the type column via EntityTypeColumn and the identity column using the EntityIdentifierColumn method.

Submit this story to DotNetKicks

Thursday, May 14, 2009

FluentNHibernate Mappings: Join

Recently Oren (Ayende) had a serious of posts on NHibernate mappings and the various options you can configure using Xml mappings. This series of posts takes those examples and shows how you can use FluentNHibernate to configure the same mappings.

This is a companion post for Oren’s post on the <join> mapping in NHibernate, here. I recommend reading his post before venturing forward.

To create a joined table mapping using FluentNHibernate you need to use the WithTable mapping function and specify the JoinedPart definition:

WithTable("Addresses", join =>

                           {

                               join.Map(prop => prop.StreetAddress1, "StreetAddress1");

                            join.Map(prop => prop.StreetAddress2, "StreetAddress2");

                            join.Map(prop => prop.City, "City");

                            join.Map(prop => prop.State, "State");

                            join.Map(prop => prop.ZipCode, "ZipCode");

                               join.WithKeyColumn("PersonId");

                           });

The WithTable mapping function has two overloads, one just taking in a string parameter and another that takes in a string parameter as well as a action that allows you to configure a JoinPart. The first overload instructs fluent nhibernate to output the table name of the class being mapped, for e.g WithTable("Persons") will generate a mapping: <class name="Person" table="Persons"> element.

The second overload outputs the <join> element in the mapping. Just like mapping a component, the JoinPart allows you to map properties in the class as belonging to another table. The only thing to be aware of here is that you are specifying the column names in the join table for your properties manually.

Now to define the join table as optional, you again need to use the SetAttribute method to output the "optional" attribute since there's no inbuilt way to specify that in the JoinPart. Below is the full mapping:

WithTable("Addresses", join =>

                           {

                               join.Map(prop => prop.StreetAddress1, "StreetAddress1");

                            join.Map(prop => prop.StreetAddress2, "StreetAddress2");

                            join.Map(prop => prop.City, "City");

                            join.Map(prop => prop.State, "State");

                            join.Map(prop => prop.ZipCode, "ZipCode");

                               join.WithKeyColumn("PersonId");

                            join.SetAttribute("optional", "true");

                           });

Submit this story to DotNetKicks

FluentNHibernate Mappings: One-To-One

Recently Oren (Ayende) had a serious of posts on NHibernate mappings and the various options you can configure using Xml mappings. This series of posts takes those examples and shows how you can use FluentNHibernate to configure the same mappings.

This is a companion post for Oren’s post on the <one-to-one> mapping in NHibernate, here. I recommend reading his post before venturing forward.

In FluentNHibernate one-to-one mappings are achieved by using the HasOne mapping method on the parent and the References method on the child. Below is the mapping for the Person entity that has a one-to-one relationship with an Employee entity:

            HasOne(prop => prop.Employee)
                .PropertyRef(prop => prop.Person);

You can also specify the actual property that HasOne uses to specify the foreign key relationship using the PropertyRef method. The above statement basically creates a mapping instruction that reads “Person has a one-to-one relationship with Employee on the Person property of the Employee entity”.

Similarly, the Employee mappings use the References mapping method to specify the bi-directional part of the relationship. Here’s the full class mapping for Employee:

    public class EmployeeMap : ClassMap<Employee>
    {
        public EmployeeMap()
        {
            WithTable("Employees");
            Id(prop => prop.Id).GeneratedBy.Native();
            Map(prop => prop.Role);
 
            References(prop => prop.Person)
                .ColumnName("PersonId")
                .FetchType.Select()
                .LazyLoad()
                .Unique();
        }

The References mapping method in EmployeeMap generates a many-to-one mapping to the Person entity. You must add the Unique mapping modifier to instruct that the many-to-one mapping maps to a unique Person instance making it effectively a one-to-one mapping. You’ll also notice that I’ve set the FetchType to Select, this is done so that associated Person instances are lazy loaded when needed.

Submit this story to DotNetKicks

Wednesday, May 13, 2009

FluentNHibernate Mappings: HasMany

Recently Oren (Ayende) had a serious of posts on NHibernate mappings and the various options you can configure using Xml mappings. This series of posts takes those examples and shows how you can use FluentNHibernate to configure the same mappings.

This is a companion post for Oren’s post on the <set> mapping in NHibernate, here. I recommend reading his post before venturing forward.

A <set> element in NHibernate’s mapping refers to a one-to many mapping. This can be represented simply in FluentNHibernate using the HasMany mapping method:

 HasMany(prop => prop.Comments);

The HasMany statement simply specifies that the entity has a one-to-many relationship with the Comment entity as represented by the Comments property.

Specifying the foreign key name.

If you need to specify the foreign key column on the relationship you can use the KeyColumnNames property and use the Add method to specify the column name:

HasMany(prop => prop.Comments)
                .KeyColumnNames.Add("CreatedBy");

The above code snippet shows that the foreign key column on the Comments relationship is named “CreatedBy”.

Fetching strategy for relationships:

By default the fetching strategy used by fluent-nhibernate for associations is not lazy loaded (for auto mapping the convention is to set lazy as true). You can override this behavior using the Lazy method

HasMany(prop => prop.Comments)
                .KeyColumnNames.Add("CreatedBy")
                .LazyLoad();

To specify that the collection should be loaded using an outer-join, use the FetchType property on the mapping. This mapping can be either; Select or Join. The first one is the default setting which uses a sparate Select statement to get the associated entities, whereas Join uses an outer join statement to get the associated entities.

HasMany(prop => prop.Comments)
                .KeyColumnNames.Add("CreatedBy")
                .LazyLoad()
                .FetchType.Join();

Note that when you specify FetchType as Join, even if you specify LazyLoad NHibernate will still pre-fetch the entities using a left outer join.

Defining an inverse relationship:

Inverse is specified by simply setting the association as Inverse()

HasMany(prop => prop.Comments)
                .KeyColumnNames.Add("CreatedBy")
                .LazyLoad()
                .FetchType.Join()
                .Inverse();

Submit this story to DotNetKicks

Tuesday, May 12, 2009

FluentNHibernate Mappings: Component

[Edit: Reformatted code snippets and removed unnecessary line breaks]

Recently Oren (Ayende) had a serious of posts on NHibernate mappings and the various options you can configure using Xml mappings. This series of posts takes those examples and shows how you can use FluentNHibernate to configure the same mappings.

This is a companion post for Oren’s post on <component> mappings in NHibernate, here. I recommend reading his post before venturing forward.

In this post I’ll show how you use FluentNHibernate instead of using NHibernate’s xml mapping files.

Based on Oren’s original post on <component> mapping, here is the full mapping file:

<class name="Person"
table="People">

<id name="Id">
<generator class="identity"/>
</id>
<property name="Name" />
<component name="Address">
<property name="Line1"/>
<property name="Line2"/>
<property name="City"/>
<property name="Country"/>
<property name="ZipCode"/>
</component>
</class>

Below are the mappings in FluentNHibernate:

Component(prop => prop.Address, mapping =>

{

     mapping.Map(prop => prop.StreetAddress1);

     mapping.Map(prop => prop.StreetAddress2);

     mapping.Map(prop => prop.City);

     mapping.Map(prop => prop.State);

     mapping.Map(prop => prop.ZipCode);

});

Basically the Component method allows you to specify which property in your entity is treated as a Component and then allow to provide mappings for the properties of the component itself.

Submit this story to DotNetKicks

Fluent NHibernate Mappings: Property

Recently Oren (Ayende) had a serious of posts on NHibernate mappings and the various options you can configure using Xml mappings. This series of posts takes those examples and shows how you can use FluentNHibernate to configure the same mappings.

This is a companion post for Oren’s post on property mappings in NHibernate, here. I recommend reading his post before venturing forward.

In this post I’ll show how you use FluentNHibernate instead of using NHibernate’s xml mapping files.

Based on Oren’s original post on <property> mapping, here is the full mapping file:

<class name="Blog"
table="Blogs">

<id name="Id">
<generator class="identity"/>
</id>
<version name="Version"/>
<property name="Title" update="false"/>
<property name="Subtitle" optimistic-lock="insert"//>
<property name="AllowsComments" insert="false"/>
<property name="CreatedAt" />
<property name="CountOfPosts"
formula="(select count(*) from Posts where Posts.Id = Id)"/>
</class>

Below is the matching FluentNHibernate mapping:

public class PersonMap : ClassMap<Person>

{

    public PersonMap()

    {

        WithTable("Persons");

        Id(prop => prop.Id)

            .GeneratedBy.Identity();

 

        Version(prop => prop.Version);

        Map(prop => prop.FirstName);

        Map(prop => prop.LastName).SetAttribute("optimistic-lock", "false");

        Map(prop => prop.DateOfBirth);

        Map(prop => prop.Active).SetAttribute("generated", "insert");

        Map(prop => prop.CountOfComments)

            .FormulaIs("(Select Count('') from Comments Where Comments.CreatedBy = Id)");

    }

}

A couple of notes:

  1. You can use the Version() method to specify a version property in your class.
  2. There is no inbuilt way to specify optimistic-lock attribute in FluentNHibernate right now, at least I couldn’t find one. But you can use the SetAttribute method to inject in the attribute value.
  3. Similarly, there is no inbuilt way to specify that a column value is generated by the database, but just like in the case of optimistic-lock, you can use the SetAttribute method to inject the attribute.
  4. FormulaIs can be used to specify a custom formula for a property.

Submit this story to DotNetKicks

NCommon 1.0 and Google code.

Well I finally got some time to move NCommon to Google code. Here’s the link:

http://code.google.com/p/ncommon/

Along with moving to Google Code, NCommon is now released as 1.0, both the source and binaries are available as a release in Google Code.

Over the next few days I’ll be adding some documentation on the Wiki pages, a lot of that coming from this blog, on how to setup and use NCommon in your projects. The tests are now referencing a private NUnit so that you don’t need to have NUnit installed.

NHibernate libraries:

This is just a note that the libraries related to NHibernate, including fluent-nhibernate and NHibernate.Linq, are binaries built from the latest trunk. So you need to have the Antlr3.runtime.dll to make NHibernate work. Similarly both fluent-nhibernate and NHibernate.Linq assemblies are built against the latest NHibernate trunk.

If you need to use NCommon with NHibernate 2.0.1 or NHibernate 2.1 Alpha 2, please update the libraries and also update fluent-nhibernate and NHibernate.Linq assemblies to not get a assembly version conflict.

Why move to Google Code.

I have been asked a couple of times why I’m moving NCommon from CodePlex to google code. The answer is because Google code is a lot faster that CodePlex and has a better project management experience than CodePlex. I started to get put off by CodePlex when I was forced to switch to IE to post responses in the Issues forum because the editor in Firefox or Safari would horribly mangle what I wrote. It may have been fixed but it took way too long for that fix to happen and since then have had issues checking in at times.

I also like the lightweight approach that Google Code has. For some reason I always feel that CodePlex is heavy or bogged down…

Anyways, there will no longer be any updates on the CodePlex site.

Submit this story to DotNetKicks