现在的位置: 首页 > 综合 > 正文

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

2012年12月18日 ⁄ 综合 ⁄ 共 12520字 ⁄ 字号 评论关闭

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

use NHibernate

go


CREATE TABLE users (

  LogonID 
varchar(20NOT NULL default '0',

  Name 
varchar(40default NULL,

  Password 
varchar(20default NULL,

  EmailAddress 
varchar(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.Demo.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镜像文件:

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


<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">


    
<class name="NHibernate.Demo.QuickStart.User, NHibernate.Demo.QuickStart" table="users">

        

        
<id name="Id" column="LogonId" type="String(20)">

            
<generator class="assigned" />

        
</id>

        

        
<property name="UserName" column="Name" type="String(40)"/>

        
<property name="Password" type="String(20)"/>

        
<property name="EmailAddress" type="String(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.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创建一个配置段落:

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

<configuration>

       
<configSections>

            
<section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.3300.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;User ID=someuser;Password=somepwd;Min Pool Size=2" 

        
/>

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

上述例子用了一个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类和后台数据库间的映射.

Configuration cfg = new Configuration();

    cfg.AddAssembly(
"NHibernate.Demo.QuickStart");


 

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管理事务.

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:

然后读取.保存并且查询你的对象吧(CRUD)

现在你可以对对象使用.Net自己的方式.你想存储一个新用户到数据库么.那么来试下这个:

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.

就如同你看到的那样.对大多数情况而言,你只需要关心业务对象,只需要告诉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:

在你知道用户号,想要获取一个对象的时候(当用户登陆网站).一旦会话打开,就像门用钥匙你就可以进入一样简单.

// 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:

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

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:

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

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 
+

抱歉!评论已关闭.