Archive

Archive for the ‘Fluent NHibernate’ Category

Fluent NHibernate 1.0 RTM

August 29, 2009 Comments off

For those who haven’t seen the twits, posts, or others, James and crew have put the final touches on and cranked out Fluent NHibernate 1.0 RTM.

There were quite a few changes (for the better) between prior releases and the 1.0 builds—especially around auto mapping and conventions.  So far, I love the changes—much more explicit and easy to configure once you get the hang of where things are located.

Congrats to everyone involved!

Download: http://fluentnhibernate.org/downloads

(New) Wiki: http://wiki.fluentnhibernate.org/Main_Page

AutoMappings in NHibernate – A Quick Runthrough

June 26, 2009 Comments off

For most of my projects, at least since I’ve moved to NHibernate/Fluent NHibernate, I’ve been trapped using the existing data structures of prior iterations.  Funky naming conventions (many due to cross-cultural, international column naming), missing data relationships, and general craziness.

Having used Fluent Mappings (creating a class that implements ClassMap<objectType>) in the past, they were a huge jump up from writing painful data objects, connecting them together, and recreating the wheel with “SELECT {column} from {table}” code.  Create a map, use the fluent methods to match column to property, and away you go.

In a recent project, I’ve had the opportunity to build a new system from the ground up.  With this, I decided to dive head first into using the AutoMappings functionality of Fluent NHibernate. 

This post is somewhat a rambling self-discussion of my explorations with AutoMappings.

What are AutoMappings?

The FluentNHibernate wiki provides a simple definition:

[…] which is a mechanism for automatically mapping all your entities based on a set of conventions.

Rather than hand-mapping each column to a property, we create conventions (rules) to map those.. automatically.  Hey look, auto…mappings.  😉

How?

Using the same fluent language, configuring AutoMapping is an exercise in implementing conventions for the logical naming and handling of data.

Fluently

    .Configure()

    .Database(MsSqlConfiguration.MsSql2005

                  .ConnectionString(cs => cs

                                              .Server(“server”)

                                              .Database(“db”)

                                              .Username(“user”)

                                              .Password(“password”)

                  )

                  .UseReflectionOptimizer()

                  .UseOuterJoin()

                  .AdoNetBatchSize(10)

                  .DefaultSchema(“dbo”)

                  .ShowSql()

    )

    .ExposeConfiguration(raw =>

                             {

                                 // Testing/NHibernate Profiler stuffs.

                                 raw.SetProperty(“generate_statistics”, “true”);

                                 RebuildSchema(raw);

                             })

    .Mappings(m =>

              m.AutoMappings.Add(AutoPersistenceModel

                                     .MapEntitiesFromAssemblyOf<Walkthrough>()

                                     .ConventionDiscovery.Setup(c =>

                                                                    {

                                                                        c.Add<EnumMappingConvention>();

                                                                        c.Add<ReferencesConvention>();

                                                                        c.Add<HasManyConvention>();

                                                                        c.Add<ClassMappingConvention>();

                                                                    })

                                     .WithSetup(c => c.IsBaseType = type => type == typeof (Entity)))

                  .ExportTo(@”.\”)

    );

As you can see above, the only difference from a fluent mappings configuration is in the actual Mappings area.  Good deal!  That helps ensure my existing work using fluent mappings could translate without too much headache.

I’ve specified four conventions.  Each of these conventions have interfaces that provide the necessary methods to ensure your rules are appied to the correct objects.

EnumMappingConvention

internal class EnumMappingConvention : IUserTypeConvention

{

    public bool Accept(IProperty target)

    {

        return target.PropertyType.IsEnum;

    }

 

    public void Apply(IProperty target)

    {

        target.CustomTypeIs(target.PropertyType);

    }

 

    public bool Accept(Type type)

    {

        return type.IsEnum;

    }

}

The great thing about these methods is they’re fluent enough to translate to English.

Accept… targets where the property type is an enumeration.

Apply… to the target that the “Custom Type Is” the property type of the target.
  NOTE: This translates from a ClassMap into: Map(x => x.MyEnumFlag).CustomTypeIs(typeof(MyEnum));

Accept… a type that is an enumeration.

ReferenceConvention

The Reference convention handles those reference relationships between our classes (and the foreign keys).

internal class ReferencesConvention : IReferenceConvention

{

    public bool Accept(IManyToOnePart target)

    {

        return string.IsNullOrEmpty(target.GetColumnName());

    }

 

    public void Apply(IManyToOnePart target)

    {

        target.ColumnName(target.Property.Name + “Id”);

    }

}

The most important part here is enforcing how your foreign keys are going to be named.  I prefer the simple {Object}Id format.

Car.Battery on the object side and [Car].[BatteryId] on the database side.

HasManyConvention

The HasManys are our lists, bags, and collections of objects.

internal class HasManyConvention : IHasManyConvention

{

 

    public bool Accept(IOneToManyPart target)

    {

        return target.KeyColumnNames.List().Count == 0;

    }

 

    public void Apply(IOneToManyPart target)

    {

        target.KeyColumnNames.Add(target.EntityType.Name + “Id”);

        target.Cascade.AllDeleteOrphan();

        target.Inverse();

    }

}

We want to make sure that we haven’t added any other key columns (the Count == 0), and then apply both the naming convention as well as a few properties.

Cascade.AllDeleteOrphan() and Inverse() allows our parent objects (Car) to add new child objects (Car.Battery (Battery), Car.Accessories (IList<Accessory>)) without separating them out.

ClassMappingConvention

Finally, the important Class mapping.  This convention ensures that our tables are named property with pluralization.

public class ClassMappingConvention : IClassConvention

{

    public bool Accept(IClassMap target)

    {

        return true; // everything

    }

 

    public void Apply(IClassMap target)

    {

        target.WithTable(PluralOf(target.EntityType.Name));

    }

}

I’m using a pluralization method from one of my base libraries that I borrowed from Hudson Akridge.  This helper method works really well and I don’t need to add additional references and libraries into my application just to handle the table names.

public static string PluralOf(string text)

  {

      var pluralString = text;

      var lastCharacter = pluralString.Substring(pluralString.Length – 1).ToLower();

 

      // y’s become ies (such as Category to Categories)

      if (string.Equals(lastCharacter, “y”, StringComparison.InvariantCultureIgnoreCase))

      {

          pluralString = pluralString.Remove(pluralString.Length – 1);

          pluralString += “ie”;

      }

 

      // ch’s become ches (such as Pirch to Pirches)

      if (string.Equals(pluralString.Substring(pluralString.Length – 2), “ch”,

                        StringComparison.InvariantCultureIgnoreCase))

      {

          pluralString += “e”;

      }

      switch (lastCharacter)

      {

          case “s”:

              return pluralString + “es”;

          default:

              return pluralString + “s”;

      }

  }

Save and build.  The ExportSchema method will generate the SQL and/or regen the database based on the specifications you’ve provided to it. and you’re ready to hit the ground running!

 

Benchmarks : Comparing LINQ to NHibernate Transforms/Grouping

Yesterday, I wrote about setting up NHibernate to query up, group, count, and transform results and return them into a control.  Why did I go to such effort?  Well, the original LINQ query I had that refined the results didn’t perform up to par.  As some may note, premature optimization is never a good practice so I needed some stats to back up the claims.

Overnight, I wrote up a quick test to query up both ways and benchmark the results.  Here’s what I found.

The “test”:

public void TEMP_quick_compare_of_linq_to_nhibernate()

{

    var schoolId = 120;

 

    var benchmark = new Benchmark();

    using (var repository = new IncidentRepository())

    {

        benchmark.Start();

        var resultsFromLinq =

            repository.GetCountByIncidentCodeWithLinq(schoolId);

        foreach (var item in resultsFromLinq)

        {

            Console.WriteLine(item);

        }

        benchmark.Stop();

        Console.WriteLine(“Linq: {0}”.AsFormatFor(benchmark.ElapsedTime));

 

        benchmark.Start();

        var resultsFromNhibernate =

            repository.GetCountByIncidentCode(schoolId);

        foreach (var item in resultsFromNhibernate)

        {

            Console.WriteLine(item);

        }

        benchmark.Stop();

        Console.WriteLine(“NHibernate: {0}”.AsFormatFor(benchmark.ElapsedTime));

    }

}

Setting up the benchmark (and the NHibernate Init) are outside of the benchmark—they’re necessary overhead.  I’m also iterating through each of the results as part of the benchmark to ensure that everything is evaluated. Past that, pretty basic.  On the database side, I’ve disabled statement caching to not sway the results as much.

With 24 records (the test data in the system), the results were pretty clear. The average of running the benchmark 100 times resulted in…

Linq: 00:00:00.7050000
NHibernate: 00:00:00.0190000

With 24 records, NHibernate was about 37x faster. 

That’s nice, but what happens in a few weeks when there are a few thousand records?  I populated a few hundred of each incident type into the system, giving me almost 4000 records (the anticipated monthly load of the system by the customer).  How’d that change our averages?

Linq: 00:00:00.8869746
NHibernate: 00:00:00.1381518

Now we’re only 6x faster with NHibernate vs. LINQ.  The duration from 24 to 4000 records for LINQ  jumped ~.18 seconds for a 25% gain where as NHibernate jumped ~.11 seconds for a 626% gain.

So, with that, my original gut feeling and assumptions were wrong.  More and more records don’t really slow down the LINQ filtering.. at least not by much.  The performance gain is still appparent between the two methods (.88 sec vs. .13 sec); however, how much of that time is eaten up by rendering, server latency, etc and not by the actual processing?

Fluent NHibernate Repository of… integers?

April 21, 2009 Comments off

I’d like to preface this by the fact that this “works” doesn’t mean it “should”.  If there’s a proper way to do this, I’m all ears. 😀

I recently needed to do some revamp to an application that queried lookup data from another data system.  The system had a collection of composite keys (age and total score) that returned a percentile score.  Easy enough; however, there are a couple dozen of these tables and I didn’t want to create a couple dozen domain objects/repositories for a SINGLE query.

Typically, the NHibernateRepository* takes a type parameter that matches to the mapped object (and provide the proper return type); however, in this case, I didn’t have a type to return, simply an integer.  So why wouldn’t that work?

public class ScoreRepository : NHibernateRepository<int>, IDisposable

With that in place, I can now add a query into Session:

public int GetConceptPercentile(int age, int total)

{

var result =

       Session.CreateSQLQuery(

“select perc from tblConcept where age = :age and total = :total”

             .SetInt32(“age”, age)

             .SetInt32(“total”, total)

.UniqueResult().ConvertTo<int>();

 

return result;

}

A few more of those, and our test looks like:

[Fact]

public void GetPercentiles_For_Student()

{

using (var repository = new ScoreRepository())

       {

              var languagePercentile =

             repository.GetLanguagePercentile(ageCalc_72months.TotalMonths, 18);

            

var motorPercentile =

             repository.GetMotorPercentile(ageCalc_72months.TotalMonths, 18);

            

var conceptPercentile =

             repository.GetConceptPercentile(ageCalc_72months.TotalMonths, 18);

 

             languagePercentile.ShouldBeEqualTo(12);

             motorPercentile.ShouldBeEqualTo(17);

             conceptPercentile.ShouldBeEqualTo(10);

}

}

Everything “appears” to be working; however, the extraneous methods that each NHibernateRepository includes (Get, GetAll, FindAll, etc) are defunct and just sitting there—very messy.

So is there a better way to use NHibernate/Fluent NHibernate WITHOUT mapping objects—those “lookup tables”?

Using Multiple NHibernate Session Factories

March 6, 2009 1 comment

A few months ago, I rewrote a few of my base repositories to follow some of the archtecture practices of the S#arp Architecture project.  I liked how easy it was to setup NHibernate*, mark domain objects, and setup mappings and highly recommend checking out their project.  Unfortunately, the whole project was a bit too bulky for what I needed and much of the functionality already existed in existing framework libraries we use at the office.

* When I mention NHibernate, I’m using Fluent NHibernate, currently at build 366 with a bit of modification to allow Oracle data access.  I’ve also enhanced the S#arp Architecture project to take advantage of the latest feature changes in Fluent NHibernate.

One pitfall, however, that I recently ran into was needing to access NHibernate multiple session factories at the same time—such as to access PeopleSoft and our internal student system to pull in demographic information.  The S#arp web session storage, by default, uses a single key opening a separate session overwrites the prior.

I found an open Issue on the S#arp tracker (#12) for such a functionality and a bit of code from Russell Thatcher to allow multiple sessions; however, I could never get it fully working—so I set off to create my own.

Updating the WebSessionStorage

To address the issue of storing multiple sessions in the HttpContext’s session state, the keys must be uniquely named when created.  To do this, I replaced the previous constructor of WebSessionStorage(HttpApplication) and added an additional parameter to create WebSessionStorage(HttpApplication, string).

This appends a name to the session key used to store the NHibernate ISession.

private readonly string CurrentSessionKey = “nhibernate.”;

 

public WebSessionStorage(HttpApplication application, string factoryKey)

{

       application.EndRequest += Application_EndRequest;

       CurrentSessionKey += factoryKey;

}

Everything else in WebSessionStorage remains the same.

NOTE: This ensures that we can find the ISession within the ASP.NET context using WebSessionStorage and isn’t required if you’re managing the the ISession yourself or using another mechanism for storage.

Updating the NHibernateSession

Since we’re looking to support multiple, keyed sessions, the NHibernateSession’s private fields of SessionFactory and SessionStorage should be changed into keyed Dictionaries.

private static readonly Dictionary<string, ISessionFactory> SessionFactories =

       new Dictionary<string, ISessionFactory>();

 

private static readonly Dictionary<string, ISessionStorage> SessionStorages =

       new Dictionary<string, ISessionStorage>();

To use these new dictionaries, we replace the change the logic in the Init method to add the factory and storage to the dictionary, rather than assign to a single variable.

public static FluentConfiguration Init(

       this FluentConfiguration configuration,

       ISessionStorage storage,

       string factoryKey)

{

       Check.Require(storage != null,

              “The session storage was null, but must be provided.”);

       Check.Require(!string.IsNullOrEmpty(factoryKey),

               “A unique key for the session factory was null, but must be provided.”);

 

       try

       {

              if (!SessionFactories.ContainsKey(factoryKey))

             {

                     SessionFactories.Add(

                           factoryKey,

                           configuration.BuildSessionFactory());

                    

                     SessionStorages.Add(

                           factoryKey,

                           storage);

 

                     return configuration;

              }

       }

       catch (HibernateException ex)

       {

              throw new

                     HibernateException(

                           “Cannot create session factory.”, ex);

       }

 

       return configuration;

}

Our Init statement, when called, then looks like, passing along the factory key with the ISessionStorage.

configuration.Init(storage, “FactoryKeyNameGoesHere”);

The Current static public property also needs to address the new Dictionary; however, cannot as a property as it needs the parameter of the factory key.  I converted this into a method that accepts the factory key and returns an ISession based on what it finds.  If it cannot find an open sesson (is null) in the dictionary, it opens a new one, sets it in the dictionary, and returns it to the caller.

public static ISession Current(string factoryKey)

{

       var session =

              SessionStorages[factoryKey].Session ??

              SessionFactories[factoryKey].OpenSession();

 

       SessionStorages[factoryKey].Session = session;

      

       return session;

}

That’s it in the NHibernateSession.

Updating the Repository & Decorating Inheriting Repositories

The Repository base class provides functionality to the CRUD methods through a protected Session property.  This property needs to be updated to call the new Current(string) method.  However, since the Repository doesn’t know, we need to find a way to communicate the “key” that a repository uses to ensure the correct session is accessed (so, for example, that our PeopleSoft queries don’t try to hit our SAP session—that confuses it. *grin*)

Randall had a great solution for this—an attribute applied to repositories that simply provides a place to store the “name” of the session.

[AttributeUsage(AttributeTargets.Class)]

public class SessionFactoryAttribute : Attribute

{

       public readonly string FactoryKey;

 

       public SessionFactoryAttribute(string factoryKey)

       {

              FactoryKey = factoryKey;

       }

 

       public static string GetKeyFrom(object myClass)

       {

              var key = string.Empty;

 

              //Get member info via reflection

              var info = myClass.GetType();

 

              //Retrieve custom attributes

              var attributes =

                     info.GetCustomAttributes(

                           typeof (SessionFactoryAttribute),

                           true);

 

              //Check for attribute

              if (attributes.Length > 0)

              {

                     var att =

                           (SessionFactoryAttribute) attributes[0];

                     key = att.FactoryKey;

              }

             

              return key;

       }

}

Now we simply decorate the inheriting repositories with SessionFactory.  Notice how the key matches what we used in the Init statement earlier.

[SessionFactory(“FactoryKeyNameGoesHere”)]

public class CourseRepository :
       NHibernateRepository<Course>, ICourseRepository, IDisposable { }

For a bit better design, you can also create a constant called, perhaps, FactoryKey or {data}FactoryKey and use that for the attributes and Init statement.  Then, if it needs changed—change it in one place.

Inside our Configuration class (PSConfiguration, for example), we have:

public const string FactoryKey = “PSProd”;

and

configuration.Init(storage, PSConfiguration.FactoryKey);

and then decorating our Repository classes:

[SessionFactory(PSConfiguration.FactoryKey)]

Now, to take advantage of our new SessionFactory attribute, we modify the Session property on our Repository base class.

protected virtual ISession Session

{

       get

       {

              var factoryKey = SessionFactoryAttribute.GetKeyFrom(this);

              return NHibernateSession.Current(factoryKey);

       }

}

Now the interface implementations (Get, Find, etc) are fetching the correct Session.

In summary, I’ve enabled accessing multiple NHibernate Session Factories from the S#arp Architecture framework (or my small implementation of it) by…

  • Updating the WebSessionStorage to accept a factory key when the session is created.
  • Updating the NHibernateSession to store multiple Factories and Storages in dictionaries and then access these dictionaries when the “current” session is requested.
  • Adding an attribute to Repositories to “name” which factory a certain repository should be selecting out of and then providing that session when called.

So far, things are working like a champ—tweaking and refactoring from here. 🙂