O/R Mapping Tools For DotNet - NHibernate -UserGuiding -Eng

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.

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

 以下是我们将实现的几个步骤:
1.创建数据库表用于永久性的.Net类.
2.创建.Net类来建立于表的永久映射.
3.创建映像文件用于通知Nhibernate如何对应.Net类的属性.
4.为NHibernate创建一个配置文件用于知晓如何连接数据库.
5.使用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):

None.gif use  NHibernate
None.gif
go
None.gif
None.gif
CREATE   TABLE  users (
None.gif  LogonID 
varchar ( 20 NOT   NULL   default   ' 0 ' ,
None.gif  Name 
varchar ( 40 default   NULL ,
None.gif  Password 
varchar ( 20 default   NULL ,
None.gif  EmailAddress 
varchar ( 40 default   NULL ,
None.gif  LastLogon 
datetime   default   NULL ,
None.gif  
PRIMARY   KEY   (LogonID)
None.gif)
None.gif
go
None.gif
None.gif


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 :

None.gif using  System;
None.gif
None.gif
namespace  NHibernate.Demo.QuickStart
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public class User
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private string id;
InBlock.gif        
private string userName;
InBlock.gif        
private string password;
InBlock.gif        
private string emailAddress;
InBlock.gif        
private DateTime lastLogon;
InBlock.gif
InBlock.gif
InBlock.gif        
public User()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public string Id 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn id; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ id = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public string UserName 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn userName; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ userName = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public string Password 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn password; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ password = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public string EmailAddress 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn emailAddress; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ emailAddress = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public DateTime LastLogon 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn lastLogon; }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
set dot.gif{ lastLogon = value; }
ExpandedSubBlockEnd.gif        }

InBlock.gif        
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gif


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镜像文件:

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



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.Demo.QuickStart.User in the Assembly NHibernate.Demo.QuickStart. 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) - but highly recommended. Users of Hibernate will notice an immediate difference. In the type a length for the String is being specified. This is needed in NHibernate because ADO.NET requires length and precision/scale IDbParameters to have those properties set before the IDbCommand can be prepared.

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).

TIP: 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.

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. Here's what one might look like:
我们还没有告诉NHibernate如何发现数据库.最常用的一种方式是在我们的应用程序配置文件中为NHibernate创建一个配置段落:

None.gif <? xml version="1.0" encoding="utf-8"  ?>
None.gif
< configuration >
None.gif       
< configSections >
None.gif            
< section  name ="nhibernate"  type ="System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"   />
None.gif    
</ configSections >
None.gif    
None.gif    
< nhibernate >
None.gif        
< add 
None.gif            
key ="hibernate.connection.provider"           
None.gif            value
="NHibernate.Connection.DriverConnectionProvider"  
None.gif        
/>
None.gif        
< add 
None.gif            
key ="hibernate.dialect"                       
None.gif            value
="NHibernate.Dialect.MsSql2000Dialect"  
None.gif        
/>
None.gif        
< add 
None.gif            
key ="hibernate.connection.driver_class"           
None.gif            value
="NHibernate.Driver.SqlClientDriver"  
None.gif        
/>
None.gif        
< add 
None.gif            
key ="hibernate.connection.connection_string"  
None.gif            value
="Server=localhost;initial catalog=nhibernate;User ID=someuser;Password=somepwd;Min Pool Size=2"  
None.gif        
/>
None.gif    
</ nhibernate >
None.gif
</ configuration >
None.gif
None.gif


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.

上述例子用了一个SqlClient的驱动,与本地的nhibernate数据库连接,使用提供的用户名和密码.你可以设置若干属性用于有选择的通过NHibernate访问数据库.
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.
NHibernate使用log4net来记录内部发生的事务.在开发应用程序的时候我推荐配置log4net来为你的场景设置合适的NHibernate日志级别.

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. Create a Configuration object
  2. Tell the Configuration about the type of objects you want to store
  3. Create a Session to your database of choice
  4. Load, Save and Query your objects
  5. Flush() your Session back to the database

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

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.
首先,创佳一个配置对象.
配置对象知道所有在DotNet类和后台数据库间的映射.

None.gif Configuration cfg  =   new  Configuration();
None.gif    cfg.AddAssembly(
" NHibernate.Demo.QuickStart " );
None.gif


 

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.

配置对象将编译所有后缀名为.hbm.xml的文件.虽然有其它方法来添加映射文件,但这可能是最容易的方法.

Then, Create a Session Object...

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

接着,创建一个会话对象.
会话对象表示与后台数据库的连接,事务表示NHibernate管理事务.

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

 


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:

然后读取.保存并且查询你的对象吧(CRUD)
现在你可以对对象使用.Net自己的方式.你想存储一个新用户到数据库么.那么来试下这个:

None.gif User newUser  =   new  User();
None.gif    newUser.Id 
=   " joe_cool " ;
None.gif    newUser.UserName 
=   " Joseph Cool " ;
None.gif    newUser.Password 
=   " abc123 " ;
None.gif    newUser.EmailAddress 
=   " joe@cool.com " ;
None.gif    newUser.LastLogon 
=  DateTime.Now;
None.gif            
None.gif    
//  Tell NHibernate that this object should be saved
None.gif
    session.Save(newUser);
None.gif
None.gif    
//  commit all of the changes to the DB and close the ISession
None.gif
    transaction.Commit();
None.gif    session.Close();
None.gif


 

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.

就如同你看到的那样.对大多数情况而言,你只需要关心业务对象,只需要告诉NHibernate你什么做.
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:
在你知道用户号,想要获取一个对象的时候(当用户登陆网站).一旦会话打开,就像门用钥匙你就可以进入一样简单.

None.gif //  open another session to retrieve the just inserted user
None.gif
    session  =  factory.OpenSession();
None.gif
None.gif    User joeCool 
=  (User)session.Load( typeof (User),  " joe_cool " );
None.gif
None.gif

 

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

你获取得用户对象是动态的!更改他的属性并且更新到数据库就是一瞬间的事情.

None.gif //  set Joe Cool's Last Login property
None.gif
    joeCool.LastLogon  =  DateTime.Now;
None.gif
None.gif    
//  flush the changes from the Session to the Database
None.gif
    session.Flush();
None.gif

 

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:

更加奇妙的是,你可以查询你的表并且返回一个包含动态对象的System.Collections.IList.看下这个:

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

None.gif


 

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:

这种查询可以返回整张表.典型情况下你想获得更多的控制权-比如列出自从去年三月14 2004 10:00 PM登陆的用户,那么你可以这么做:

None.gif IList recentUsers  =  session.CreateCriteria( typeof (User))
None.gif                    .Add(Expression.Expression.Gt(
" LastLogon " new  DateTime( 2004 03 14 20 0 0 )))
None.gif                    .List();
None.gif
None.gif    
foreach (User user  in  recentUsers)
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        System.Diagnostics.Debug.WriteLine(user.Id 
+ " last logged in at " + user.LastLogon);
ExpandedBlockEnd.gif    }

None.gif
None.gifThere are a wealth 
None.gif


 

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.
这篇文章还有很多查询方法,但这只不过给你认识下Hibernate的一部分功能.

...And Finally Close() your session. This will free up the ADO.NET connection that NHibernate is using.
最后关闭你的会话.释放被NHibernate使用的ADO.Net连接.

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



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). 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.

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值