26 March 2007

NHibernate Tutorial, Jumptree Forum Part 4 - Setup and Add Category

Part I - Why I choose Nhiberneate
Part II - Spring.Net, Setup Nhibernate Support

Part 3 - Jumptree Nhibernate Forum Part 3 -  Getting Ready
Part 5 - Different Ways of Mapping File Configuration

Jumptree Forum Database Setup
 
In my previous post, I talked about the Nhibernate Web example. Now that we understood the basic of how the example web is set up, let’s talk about how are we going to implement our Jumptree forum.

The transition to NHibernate is better if we follow our traditional design process and start with the database tables and design of its relationships. Here is my database design for the forum.

Let me explain. 

First of all, each discussion can have multiple comments. Such the “One-To-Many” relationship between “JumptreeForum_Dicussions” and “JumptreeForum_DiscussionComments”.  

Second, each discussion can belong to many categories at the same time and each category can have many discussions, such it’s the typical “Many-To-Many” relationship. The intermediate table “JumptreeForum_DiscussionsCategories” will hold this “Many to Many relationship” and we will later on map our NHibernate files accordingly.

It’s important that you understand why our forum is designed the way it is before we continue further, as everything that we have to do later on depends on our understanding of the db structure.

Jumptree Forum Project Structure


In my part II of the series, I mentioned I will be using Spring.Net for our Nhibernate project, however, the plan is to first develop a pure NHibernate solution for our Forum and then we’ll integrate Spring.NET into our solution later on. This way, you will see why Spring.Net is needed and the effort it saves you when it comes to writing an NHibernate application.

Anyway, so let’s continue with the Nhibernate setup.  Unlike the NHibernate web example provided by the Nihernate download,  I wanted a three tier structure. The first thing I did is open up Visual Studio 2005 and I added a “Blank Solution”.  When it’s done, I added a “ASP.NET Web site project”, a class library “Jumptree.Forum.BusinessEntities” project and a class library “Jumptree.Forum.DataAccess” to the solution.  (I will have another layer for business logic later on , but at this point, I just want the basic to make sure I’m able to use Nhibernate)

Here are the projects’ relationships.

  1. Jumptree.Forum.DataAccess references “Jumptree.Forum.BusinessEntities”

  2. ASP.Web site references “Jumptree.Forum.DataAccess” and “Jumptree.Forum.BusinessEntities”.

    In addition, you need to reference the following Nhibernate 1.2 related libraries for your ASP.net web site which can be found under “[Nhiberneate 1.2 directory]/bin/net-2.0/” directory (assuming you’ve compiled the Nhibernate 1.2 source)

    Castle.DynamicProxy.dll
    Iesi.Collections.dll
    log4net.dll
    NHibernate.dll

In addition, as I mentioned in my previous article, there are two classes in the Nhibernate Web example that are important to Nhibernate data access. “CurrentSessionModule.cs” and “ExampleApplication.cs”.  So what I did is copy them into my ASP.Web site’s /App_Code” directory for use later on.

This is a screen shot of my project structure



 

Jumptree Forum Configuration


Having the project structure out of our way, if you look at the NHibernate Example Web, the first thing to do is to configure your “web.config” inside the web project.

Add this section first to the top of your configuration file. 


<configuration>

      <configSections>

            <section name="nhibernate"

                         type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"

                         requirePermission="false" /><!-- Important under Medium Trust -->

            <section name="log4net"

                     type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"

                     requirePermission="false" /><!-- Important under Medium Trust -->

      </configSections>

            ….

</configuration>


Followed by the detailed configuration of the two sections we just added above. (Place them after the <configSections></configuration> tags.



      <nhibernate>

            <add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />

            <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />

            <add key="hibernate.connection.connection_string" value="Data Source=192.168.2.3;initial catalog=nhibernate;Persist Security Info=True;User ID=sa;Password=sa" />

            <add key="hibernate.bytecode.provider" value="null" /><!-- Important under Medium Trust -->

            <add key="hibernate.current_session_context_class" value="managed_web" />

      </nhibernate>

      <log4net>

            <!-- Define some output appenders -->

            <appender name="rollingFile" type="log4net.Appender.RollingFileAppender,log4net" >

        <param name="File" value="log.txt" />

        <param name="AppendToFile" value="true" />

        <param name="RollingStyle" value="Date" />

        <param name="DatePattern" value="yyyy.MM.dd" />

        <param name="StaticLogFileName" value="true" />

        <layout type="log4net.Layout.PatternLayout,log4net">

          <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &lt;%X{auth}&gt; - %m%n" />

        </layout>

      </appender>

      <!-- Setup the root category, add the appenders and set the default priority -->

      <root>

        <priority value="ALL" />

        <appender-ref ref="rollingFile" />

      </root>

      </log4net>



Basically, these configurations set up the database connection and log4net configuration to log outputs to “log.txt” file. Change to your corresponding IP address and database accordingly.

There are a few things  though.  

Notice the connection setting

<add key="hibernate.connection.connection_string" value="Data Source=192.168.2.3;initial catalog=nhibernate;Persist Security Info=True;User ID=sa;Password=sa" />


It’s different from the Nhibernate example which looks something like


<add key="hibernate.connection.connection_string" value="Server=192.168.2.3 initial catalog=nhibernate;Integrated Security=true" />


The reason is I couldn’t get it to connect by using the original connecting string. Obviously, to suit my need, I had to change it. So if you are connecting to a remote sql server like me in a shared hosting environment, you need to use mine.

Second, notice the comment in regards to “Medium Trust”. It’s really good that the Nhibernate example mentioned these, otherwise, you might research on these issues forever

Make sure requirePermission="false" is set to the two sections like above and in addition, make sure <add key="hibernate.bytecode.provider" value="null" /> As it’s another must have if you need to run Nhibernate under medium trust.

Jumptree Forum Nhibernate Classes and Mapping File

Next, take a look at my screen shot, I added four “POCO” .cs classes to my “Jumptree.Forum.BusinessEntities” project. Exactly one class per database table. 

JumptreeForum_Categories.cs

JumptreeForum_DiscussionComments.cs

JumptreeForum_Discussions.cs

JumptreeForum_DiscussionsCategories.cs


For this article, I’ll be working with “JumptreeForum_Categories”. Here is the source code of my “Jumptree_Categories.cs” , like I said, it’s really nothing special.

using System;

using System.Collections.Generic;

using System.Text;

namespace Jumptree.Forum.BusinessEntities

{

    public partial class JumptreeForum_Categories

    {

        public JumptreeForum_Categories()

        {

        }

        public JumptreeForum_Categories(System.Int32 categoryID, System.String createdBy, Nullable<System.DateTime> createdOn, System.String projectCategoryName, System.String updatedBy, Nullable<System.DateTime> updatedOn)

        {

            this.categoryIDField = categoryID;

            this.createdByField = createdBy;

            this.createdOnField = createdOn;

            this.projectCategoryNameField = projectCategoryName;

            this.updatedByField = updatedBy;

            this.updatedOnField = updatedOn;

        }

        private System.Int32 categoryIDField;

        public System.Int32 CategoryID

        {

            get { return this.categoryIDField; }

            set { this.categoryIDField = value; }

        }

        private System.String createdByField;

        public System.String CreatedBy

        {

            get { return this.createdByField; }

            set { this.createdByField = value; }

        }

        private Nullable<System.DateTime> createdOnField;

        public Nullable<System.DateTime> CreatedOn

        {

            get { return this.createdOnField; }

            set { this.createdOnField = value; }

        }

        private System.String projectCategoryNameField;

        public System.String ProjectCategoryName

        {

            get { return this.projectCategoryNameField; }

            set { this.projectCategoryNameField = value; }

        }

        private System.String updatedByField;

        public System.String UpdatedBy

        {

            get { return this.updatedByField; }

            set { this.updatedByField = value; }

        }

        private Nullable<System.DateTime> updatedOnField;

        public Nullable<System.DateTime> UpdatedOn

        {

            get { return this.updatedOnField; }

            set { this.updatedOnField = value; }

        }

    }

}

Now that we have the database, we have the “POCO” classes, the next obvious thing to do is create our “Mapping” file.  If you looked at the screen shot, I created a “Mapping” directory under “Jumptree.Forum.BusinessEntities” and a “JumptreeForum_Categories.hbm.xml” in corresponds to the “JumptreeForum_Categories.cs” file. 

Here is the content.

<?xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"

                   assembly="Jumptree.Forum.BusinessEntities"

                   namespace="Jumptree.Forum.BusinessEntities"

                   >

  <class name="JumptreeForum_Categories" lazy="false">

    <id name="CategoryID">

      <generator class="native" />

    </id>

    <property name="ProjectCategoryName" />

    <property name="CreatedBy" />

    <property name="CreatedOn" />

    <property name="UpdatedBy" />

    <property name="UpdatedOn" />

  </class>

</hibernate-mapping>


One thing important! Make sure this .xml ‘s  “Build Action” property in visual studio is compiled as “Embedded Resource”. (I don’t know why it has to be this way, just read from the official forum that it has to be done this way, so let’s do that please)

Setting Up Nhibernate To Use The Mapping File in ASP.NET 2.0

To ensure your website’s Nhibernate will be able to use this mapping file, in the “ExampleApplication.cs” I mentioned previously, you have to set it up by doing

static ExampleApplication()

{

      log4net.Config.XmlConfigurator.Configure();

Configuration = new NHibernate.Cfg.Configuration()                .AddAssembly(Jumptree.Forum.BusinessEntities);

      SessionFactory = Configuration.BuildSessionFactory();

}



So what have we done so far?  It’s simple really.  First, we created a POCO class that has properties that maps to the exact columns of the table in the database.

Then, we created a mapping file and described the content of the class’s property.

Lastly, in our “ExamplApplication.cs” (an HTTPApplication object), we added the assembly “Jumptree.Forum.BusinessEntities” which the “POCO” classes and mapping file belongs to.

Test Nhibernate

So now we have everything setup, how do we know if it’s working. Well, I created a category page with a textbox and a submit button to add the category. The source code of the add category looks like this


protected void AddCategory(object sender, EventArgs e)

{

  String categoryName = CategoryNameTextBox.Text;

  JumptreeForum_Categories category = new JumptreeForum_Categories();

  category.ProjectCategoryName = categoryName;

  ExampleApplication.GetCurrentSession().Save(category);

}


Checked the database, bang, it works.  Very simple and I didn’t write one line of data access logic. Very cool.


One thing I have to point out, there are a few tricks and tips here in regards to different ways of writing the mapping file and hook up to Nhibernate in ASP.net 2.0.   

In the next post, I’ll dedicate an entire post in regards to different ways of doing it. Stay Tuned!

 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

Comment Policy: No HTML allowed. URIs and line breaks are converted automatically. Your e–mail address will not show up on any public page.

(required) 
(optional)
(required)