Thursday, March 19, 2009

Fluent NHibernate Configured Via Dependency Injection

I remember having to reference this “best practice” post when setting up a new project utilizing NHibernate.  What a nightmare.  Thankfully, there’s been some really positive activity on the Fluent NHibernate project, and configuration has become much more straightforward.  In this post I am going to share my experience configuring NHibernate using:

Fluent NHibernate
Ninject
MySQL (Configuring any common database platform is trivial once you’ve seen it done)

To get my head around the basic configuration, I read the tutorial at the Fluent NHibernate site: http://fluentnhibernate.org/

After reading the tutorial, I had a good idea of the external dependencies I’d need to “inject” into my app.

Configuring the Repository

The primary point of entry for any data transferred to and from my database is via my repository.  NHibernate’s ISession is what I will interface with to make queries, so I’m going to need that object created and injected into my repository.

Example of a simple repository:

    public class Repository : IRepository

    {

        private ISession _session;

 

        public Repository(ISession session)

        {

            _session = session;

        }

 

        public void Save<T>(T entity) where T : DomainEntity

        {           

        }

 

        public T Load<T>(int id) where T : DomainEntity

        {

        }

 

        public IQueryable<T> Query<T>() where T : DomainEntity

        {

        }

 

        public IQueryable<T> Query<T>(Expression<Func<T, bool>> where) where T : DomainEntity

        {

        }

    }

The constructor of my class takes an instance of ISession.  This is where the dependency will be injected into my Repository class.

Widdling down the “Best Practice” article

The most important part of an NHibernate configuration is your management of the SessionFactory and Session objects.  The SessionFactory object is expensive to create, and should be made a Singleton.  The ISession object should be retained for the lifecycle of the current request if you’re working on a web application.  For a non-web project the lifecycle of the ISession should be kept around one per thread.

Many (if not all) of the major dependency injection frameworks offer this type of “lifecycle management” out of the box.  Ninject is no exception; here is how I accomplished it:

    internal class IoCConfiguration : StandardModule

    {

        public override void Load()

        {

            Bind<IRepository>().To<Repository>();

            Bind<INHibernateSessionFactoryBuilder>().To<NHibernateSessionFactoryBuilder>().Using<SingletonBehavior>();

 

            Bind<ISession>().ToMethod(ctx => ctx.Kernel.Get<INHibernateSessionFactoryBuilder>()

                .GetSessionFactory()

                .OpenSession())

                .Using<OnePerRequestBehavior>();

        }

    }

Due to the expressive nature of the API, this code is really self-explanatory.  Just for fun, compare this code with the mess from the NHibernate best practices article I mentioned eariler (http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx). 

For completeness, here is the code to configure NHibnerate via Fluent Nhibernate for a MySql database:

    public class NHibernateSessionFactoryBuilder : INHibernateSessionFactoryBuilder

    {

        private ISessionFactory _sessionFactory;

 

        public ISessionFactory GetSessionFactory()

        {

            if(_sessionFactory == null)

            {

                _sessionFactory = CreateSessionFactory();

            }

 

            return _sessionFactory;

        }

 

        private ISessionFactory CreateSessionFactory()

        {

            return Fluently.Configure()

                .Database(MySQLConfiguration.Standard.ConnectionString(c => c.FromAppSetting("DBConnString")))

                .Mappings(m => m.AutoMappings.Add(AutoPersistenceModel.MapEntitiesFromAssemblyOf<DomainClass>()

                                                .Where(w => w.BaseType == typeof(DomainEntity))

                                                .ConventionDiscovery.Add<PrimaryKeyConvention>()

                                                .WithSetup(convention =>

                                                {

                                                    convention.FindIdentity = t => t.Name == "Id";

                                                    convention.IsBaseType = type => type == typeof (DomainEntity);

                                                }

                                                )))

                .BuildSessionFactory();

        }

    }

This is all best explained by the Fluent Nhibernate wiki (which is excellently written).

All this is a first swag, and I’d love to hear how it could be improved.  Please leave a comment if you’ve got any questions or if you know of a way it can be better!

Thursday, March 05, 2009

Content Not Being Indexed in Sitefinity

This post will be a little esoteric.  I’m working on a Sitefinity project, and one of the features we wanted to implement was the built in site search module.

After configuring the search module everything appeared to be working properly, but after looking a little closer we realized that none of our site content was being indexed.  The only thing that was being indexed was each page’s meta tags.  I found out in one of the Sitefinity forums that you can control what gets indexed on the site by using an XML configuration file.  You can find your site’s configuration file in this path: /%AppDirectory%/App_Data/Search/%IndexName%/fieldsInfoProvider.xml

Here is what the file looks like when you set up a new index:

fieldsinfoproviderOrig

Here’s what the attributes mean:
name= This attribute is for the reader.  You can name it whatever you want.
weight= Gives weight to the content in the search results.  (Eg: Items weighted higher will return higher in the search results than lesser weighted items)
indexAttribute= Use this attribute to index all tags with a certain attribute.
filterTag= Use this to tell Sitefinity that you want to index by tag name. 
filterAttributes= Use this to filter the attributes by value.

In the site I am building, I want an entire HTML node to be indexed it happens to be:

<div id=”primary”></div>

So to add this content to my index, I added a field node in the fieldsInfoProvider.xml file as such:

 fieldsinfoprovider

If I wanted to add a HTML node by class, I could have changed the filterAttributes= attribute to “class:someCSSClass”.  If my HTML node was a <UL>, I’d change filterTag= “UL”.