Justin.Lu----Position

  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  4 随笔 :: 6 文章 :: 3 评论 :: 0 Trackbacks

What is NHibernate

NHibernate is a .NET based object persistence library for relational databases. NHibernate is a port of the excellent Java Hibernate relational persistence tool.

NHibernate handles persisting your .NET objects to and from an underlying relational database. Rather than you having to write SQL to get your objects in and out of the database, NHibernate takes care of this for you. Your code only need be concerned with your objects, NHibernate generates the SQL and makes sure that things end up in the correct tables and columns.

Why this Guide?
Anybody who is at all familiar with Hibernate will recognize this as being really similar to Glen Smith's A Hitchhiker's Guide to Hibernate. The content is based on that guide so all of the credit needs to be given to him.

NHibernate's documentation is not anywhere near the point that Hibernate's documentation is. However, the project's are similar enough that the reader should be able to look at Hibernate's documentation and get a very good feel for how NHibernate works.

This doc is intended to get you up and running with NHibernate as quickly as possible. It will cover how to persist a simple object to a table. For more complex examples please see the NUnit test that come with the code.

Translations of this Guide

Israel Aéce has written a version of the Quick Start in Portuguese.

Irwan Azam has written a version of the Quick Start in Bahasa Malaysia.

Simone Busoli has written a version of the Quick Start in Italian.

First Things First

You'll be needing an NHibernate distribution. Simply download the latest copy, and unzip the contents into a folder.

The Development Process

NHibernate is going to have some tools to help you generate a schema (in codebase now), generate classes from mapping files (on the drawing board), and to update a schema (suggestion from a new developer). However, for this example we are going to assume everything from setting up the table to coding the .NET class is done manually. Here are the steps we are going to perform:

  1. Create the table to persist the .NET Class to.
  2. Create a .NET Class that needs to be persisted.
  3. Create a mapping file so NHibernate knows how to persist the .NET Class' Properties
  4. Create a configuration file for NHibernate to know how to connect to your Database
  5. Use the NHibernate API

Step 1: Writing the SQL

The example we're working through is a very simple one. Consider you've developing a basic user management subsystem for your website. We'll use a Users table that looks like this (I am assuming you already have a database setup - in my case I am calling it NHibernate):

use NHibernate
go

CREATE TABLE users (
  LogonID nvarchar(
20) NOT NULL default '0',
  Name nvarchar(
40default NULL,
  Password nvarchar(
20default NULL,
  EmailAddress nvarchar(
40default NULL,
  LastLogon datetime 
default NULL,
  PRIMARY KEY  (LogonID)
)
go

 

I'm using MS Sql Server 2000, but feel free to use any kind of database you've got a .NET Data Provider driver for. We've got a User table with a Logon ID, Full Name, Password, Email and date of last logon. Pretty standard sort of deal. Next step is to write a .NET Class to handle a given User

Step 2: Creating the .NET Class

When we get a bunch of Users in memory, we'll need some sort of object to hold them for us. NHibernate works via reflection on Properties of the objects, so we'll need to add Properties to the Class we want to persist. A simple Class that can be persisted with NHibernate looks like :

using System;

namespace NHibernate.Examples.QuickStart
{
    
public class User
    
{
        
private string id;
        
private string userName;
        
private string password;
        
private string emailAddress;
        
private DateTime lastLogon;


        
public User()
        
{
        }


        
public string Id 
        
{
            
get return id; }
            
set { id = value; }
        }


        
public string UserName 
        
{
            
get return userName; }
            
set { userName = value; }
        }


        
public string Password 
        
{
            
get return password; }
            
set { password = value; }
        }


        
public string EmailAddress 
        
{
            
get return emailAddress; }
            
set { emailAddress = value; }
        }


        
public DateTime LastLogon 
        
{
            
get return lastLogon; }
            
set { lastLogon = value; }
        }

        
    }

}

In our example above, we've made the Properties and the Constructor public - but that's not a requirement for NHibernate - it can use public, protected, internal, or even private Properties to persist your data.

Step 3: Writing the Mapping File

So we've now got our SQL table, and the .NET Class that's going to map to it. We still need a way to tell NHibernate how to map from one to the other. This is accomplished via a mapping file. The cleanest (most maintainable) way is to write one mapping file per Class, and if you name it YourObject.hbm.xml and put it in the same directory as your Class, NHibernate will make things even easier for you. Here's an example of what User.hbm.xml might look like:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
    
<class name="NHibernate.Examples.QuickStart.User, NHibernate.Examples" table="users">
        
<id name="Id" column="LogonId" type="String" length="20"> 
            
<generator class="assigned" /> 
        
</id> 
        
<property name="UserName" column= "Name" type="String" length="40"/> 
        
<property name="Password" type="String" length="20"/> 
        
<property name="EmailAddress" type="String" length="40"/>
        
<property name="LastLogon" type="DateTime"/>
    
</class>

</hibernate-mapping>

 

Let's have a look at some lines of interest in our file. The first tag of interest is the class tag. Here we map from the Type name (Class name and Assembly) to the users table in our database. This is slightly different than Hibernate. You have to tell NHibernate where to load the Class from. In this case we are loading the Class NHibernate.Examples.QuickStart.User in the Assembly NHibernate.Examples. NHibernate follows the same rules of loading a Type as the .NET Framework - so if you have any confusion about how to specify the Type see the .NET Framework SDK.

Let's skip the id tag for a moment and talk about the property tags. A cursory scan will show this is where the work is being done. The name attribute is the Property on our .NET Class, and the column is the name of the field in our database. The type attribute is optional (NHibernate will use reflection for a best-guess if you leave it out).

Ok. Let's return to that id tag. You may have guessed that this tag has something to do with mapping to the primary key of the table. You'd be right. The form of the ID tag is very similar to the property tags we just looked at. We map from the Property (name) to the target database field (column).

The embedded generator tag tells NHibernate how it should produce the primary key (it's quite happy to generate one for you, of whatever type you prefer, but you'll need to tell it how). In our case, we set it to assigned, meaning that our object is going to generate its own keys (the User object will always need to have a UserID after all). If you're keen to let NHibernate generate keys for you, you'll be interested in class settings like uuid.hex and uuid.string (check out the docs for more info).

Useful Information

If you are using Visual Studio .NET to compile make sure that you set the Build Action of the User.hbm.xml file to Embedded Resource. The mapping file will now be a part of the Asssembly. The subtle detail's importance will be evident later.

Useful Information

If the only change you make between builds is to a mapping file then you must Rebuild the project. Visual Studio .NET will not recompile a project if only a hbm.xml file was changed.

Step 4: Creating a Configuration File for Your Database

We still haven't told NHibernate where to find our database. The most straightforward way is to feed NHibernate a configuration section from your application's config file. This is the equivalent of using a Properties file with Hibernate. Here's what one might look like:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  
<configSections>
    
<section 
      
name="nhibernate" 
      type
="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" 
    
/>
  
</configSections>
    
  
<nhibernate>
    
<add 
      
key="hibernate.connection.provider"          
      value
="NHibernate.Connection.DriverConnectionProvider" 
    
/>
    
<add 
      
key="hibernate.dialect"                      
      value
="NHibernate.Dialect.MsSql2000Dialect" 
    
/>
    
<add 
      
key="hibernate.connection.driver_class"          
      value
="NHibernate.Driver.SqlClientDriver" 
    
/>
    
<add 
      
key="hibernate.connection.connection_string" 
      value
="Server=localhost;initial catalog=nhibernate;Integrated Security=SSPI" 
    
/>
  
</nhibernate>
</configuration>

The example above uses a SqlClient driver, connects to the nhibernate database on localhost, and uses the supplied username and password. There are a bunch of other properties you can set to "tune" how NHibernate accesses your database of choice. Once again, checkout the doco for detailed info.

log4net

Please note that the above configuration file does not have any information about configuring log4net. NHibernate uses log4net to log what is happening internally. In a production application I would recommend configuring log4net and setting NHibernate to the appropriate log level for your scenario. Configuring log4net Logging

Step 5: Start doing Magic with NHibernate

All the hard work has now been done. If all has gone well so far, you'll have the following:

  • User.cs - your C# Class to persist
  • User.hbm.xml - your NHibernate mapping file
  • app.config - your configuration settings with ADO.NET connection info (you can do this in code if you like)
  • A SQL User table in your database

Making use of NHibernate in your source is pretty straightforward. The nutshell edition goes:

  1. Add a reference to NHibernate.dll (in the 'bin' folder where you installed NHibernate)
  2. Create a Configuration object
  3. Tell the Configuration about the type of objects you want to store
  4. Create a Session to your database of choice
  5. Load, Save and Query your objects
  6. Flush() your Session back to the database

Let's have a look at some source to make it all much clearer.

To save typing, add the following using statements to the beginning of your class

using NHibernate;
using NHibernate.Cfg;

First, Create a Configuration Object...

The Configuration object has knowledge of all the mappings that are going on between .NET Classes and the backend database.

Configuration cfg = new Configuration();
cfg.AddAssembly(
"NHibernate.Examples");

The Configuration object will look through the Assembly for any files ending in .hbm.xml. There are other ways to add the Mapping files, but this is probably the easiest.

Then, Create a Session Object...

The ISession object represents a connection to your backend database and the ITransaction represents a NHibernate managed Transaction.

ISessionFactory factory = cfg.BuildSessionFactory();
ISession session 
= factory.OpenSession();
ITransaction transaction 
= session.BeginTransaction();

Then Load, Save and Query your Objects!

Now you just use your objects in a .NET-native way. Would you like to store a new User in the database? Try something like this:

User newUser = new User();
newUser.Id 
= "joe_cool";
newUser.UserName 
= "Joseph Cool";
newUser.Password 
= "abc123";
newUser.EmailAddress 
= "joe@cool.com";
newUser.LastLogon 
= DateTime.Now;
            
// Tell NHibernate that this object should be saved
session.Save(newUser);

// commit all of the changes to the DB and close the ISession
transaction.Commit();
session.Close();

As you can see, the great thing about NHibernate is the low overhead. Go ahead and query your database and verify that you see the new record in the users table. For the most part you just worry about your business objects, and tell NHibernate when you're done.

Let's say you want to retrieve an object when you know the user ID (eg. During a login process to your site). Once a session is opened it's a one-liner; pass in the key and you're done:

// open another session to retrieve the just inserted user
session = factory.OpenSession();

User joeCool 
= (User)session.Load(typeof(User), "joe_cool");

The User object you get back is live! Change its properties and it will get persisted to the database on next Flush().

// set Joe Cool's Last Login property
joeCool.LastLogon = DateTime.Now;

// flush the changes from the Session to the Database
session.Flush();

All you had to do to get NHibernate to write the changes you made was to ask it to Flush the Session. Go ahead and query your database through its tools to verify the Property LastLogin was updated for "joe_cool".

Even better, you can query your table and get back a System.Collections.IList of live objects. Try something like this:

IList userList = session.CreateCriteria(typeof(User)).List();
foreach(User user in userList)
{
    System.Diagnostics.Debug.WriteLine(user.Id 
+ " last logged in at " + user.LastLogon);
}

This query will return the whole table. Typically you'll want a lot more control - like list the Users who have logged in after March 14, 2004 10:00 PM, so you'll do something like:

IList recentUsers = session.CreateCriteria(typeof(User))
                .Add(Expression.Expression.Gt(
"LastLogon"new DateTime(200403142000)))
                .List();

foreach(User user in recentUsers)
{
    System.Diagnostics.Debug.WriteLine(user.Id 
+ " last logged in at " + user.LastLogon);
}

There are a wealth of querying options in the documentation, but this will give you an idea of the kind of power Hibernate offers you.

...And Finally Close() your session. This will free up the ADO.NET connection that NHibernate is using.

// tell NHibernate to close this Session
session.Close();

And that is it...
You've created objects, persisted them, and retrieved (via Criteria queries and key lookup). You've gotta be happy with that!
Now that you've got a feel for NHibernate, you'll be well served by having a good look through the extensive documentation that comes with Hibernate 2.0.3 (remember - the docs in NHibernate are still in the early stages, this is just a copy of the Hibernate docs). There's a world of cool stuff to explore like handling one-to-many SQL mapping, persisting sorted and nested collections, tuning performance and much more.

Also check out the documentation area of the wiki, where you also find the FAQ and a link to the forum!

Enjoy! And Happy NHibernating!

Mike Doerfler

Once again - all credit should go to Glen Smith and his article that served as the template for this article - A Hitchhiker's Guide to Hibernate

Updated: 2005-05-19 to include installation instructions & adding NHibernate reference and using statements.

Updated: 2004-10-07 for ddl changes to nvarchar.

Updated: 2004-08-05 for changes with type="" attribute.

Published: 2004-03-21

posted on 2005-12-20 15:44 Justin 阅读(319) 评论(0)  编辑 收藏 引用 所属分类: .Net
只有注册用户登录后才能发表评论。