一:介紹
NHibernate 是一個基於.Net 的針對關系型數據庫的對象持久化類庫。Nhibernate 來源於非常優秀的基於Java的Hibernate 關系型持久化工具。
NHibernate 從數據庫底層來持久化你的.Net 對象到關系型數據庫。NHibernate 為你處理這些,遠勝於你不得不寫SQL去從數據庫存取對象。你的代碼僅僅和對象關聯,NHibernat 自動產生SQL語句,並確保對象提交到正確的表和字段中去。
二:ORM
對象-關系映射(OBJECT/RELATION MAPPING,簡稱ORM),是隨着面向對象的軟件開發方法發展而產生的。面向對象的開發方法是當今企業級應用開發環境中的主流開發方法,關系數據庫是企業級應用環境中永久存放數據的主流數據存儲系統。對象和關系數據是業務實體的兩種表現形式,業務實體在內存中表現為對象,在數據庫中表現為關系數據。內存中的對象之間存在關聯和繼承關系,而在數據庫中,關系數據無法直接表達多對多關聯和繼承關系。因此,對象-關系映射(ORM)系統一般以中間件的形式存在,主要實現程序對象到關系數據庫數據的映射。
三:常用對象
SessionFactory(NHibernate.ISessionFactory) | 對屬於單一數據庫的編譯過的映射嗯間的一個線程安全的,不可變的緩存快照。它是Session的工廠,是ConnectioProvider的客戶。可以持有一個可選的(第二級)數據緩存,可以在進程級別或集群級別保存可以在事務中重用的數據。 |
會話Session(NHibernate.ISession) | 單線程,生命期短促的對象,代表應用程序和持久化層之間的一次對話。封裝了一個ADO.NET連接。也是Transaction的工廠。保存有必需的(第一級)持久化對象的緩存,用於遍歷對象圖,或者通過標識符查找對象 |
持久化對象(Persistent)及其集合(Collection) | 生命期短促的單線程對象,包含了持久化狀態和商業功能。它們可能是普通的對象,唯一特別的是他們現在從屬於且僅從屬於一個Session。一旦Session被關閉,他們都將從Session中取消聯系,可以在任何程序層自由使用(比如,直接作為傳送到表現層的DTO,數據傳輸對象)。 |
臨時對象(Transient Object)及其集合(Collection) | 目前沒有從屬於一個Session的持久化類的實例。它們可能是剛剛被程序實例化,還沒來得及被持久化,或者是被一個已經關閉的Session所實例化的。 |
事務Transaction(NHibernate.ITransaction) | (可選)單線程,生命期短促的對象,應用程序用它來表示一批工作的原子操作。是底層的ADO.NET事務的抽象。一個Session某些情況下可能跨越多個Transaction事務。 |
ConnectionProvider(NHibernate.Connectin.ConnectionProvider) | (可選)ADO.NET連接的工廠,從底層的IDbConnection抽象而來。對應用程序不可見,但可以被開發者擴展/實現。 |
TransactionFactory(net.sf.hibernate.TransactionFactory) | (可選)事務實例的工廠,對應用程序不可見,但可以被開發者擴展/實現 |
ICriteria | ICriteria是Expression(表達式)數據加載接口,Expression是一個關系表達式組合,通過它能產生SQL語句的Where部分, 用戶需要通過ISession來間接調用它。 |
IQuery | IQuery是HQL數據加載接口,HQL(Hibernate Query Language)是NHB專用的面向對象的數據查詢語言,它與數據庫的SQL有些類似,但功能更強大!同ICriteria一樣,也需要通過ISession來間接調用它。 |
四:栗子
Nhibernate支持各大主流的數據庫,本文中使用的是mysql數據庫。看Nhibernate的配置文件,文件名 NHibernate.cfg.xml
<?xml version="1.0" encoding="utf-8" ?> <!-- Add this element --> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" > <session-factory name="NHibernate.Test"><!--命名空間--> <!--定制IDriver的類型--> <property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property> <!--用來獲得連接的連接字符串--> <property name="connection.connection_string"> initial catalog=db_test;Data Source=xxx.xxx.x.xx;User Id=test;Password=test; pooling=true;min pool size=5; max pool size=100;Connection Timeout=100; </property> <!--NHibernate方言(Dialect)的類名 - 可以讓NHibernate使用某些特定的數據庫平台的特性--> <property name="dialect">NHibernate.Dialect.MySQL5Dialect</property> <mapping assembly="NHibernate.Test"/> </session-factory> </hibernate-configuration>
NHibernate方言(Dialect)與數據庫的對應關系
RDBMS | 方言 |
DB2 | NHibernate.Dialect.DB2Dialect |
PostgreSQL | NHibernate.Dialect.PostgreSQLDialect |
MySQL | NHibernate.Dialect.MySQLDialect |
Oracle (any version) | NHibernate.Dialect.OracleDialect |
Oracle 9/10g | NHibernate.Dialect.Oracle9Dialect |
Sybase | NHibernate.Dialect.SybaseDialect |
Microsoft SQL Server 2000 | NHibernate.Dialect.MsSql2000Dialect |
Microsoft SQL Server 7 | NHibernate.Dialect.MsSql7Dialect |
Firebird | NHibernate.Dialect.FirebirdDialect |
五:數據庫表映射xml,在項目中添加 nhibernate-configuration.xsd和 nhibernate-mapping.xsd 可以獲得智能提示
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false"> <class name="NHibernate.Test.Entity.UserModel, NHibernate.Test" table="user" lazy="false" discriminator-value="0"> <id name="Id" column="Id" unsaved-value="0" type="Int32"> <generator class="increment" /> </id> <property name="UserName" column="UserName" type="String" length="100"/> <property name="Age" column="Age" type="Int32"/> </class> </hibernate-mapping>
hibernate-mapping 的對應屬性,這個元素包括四個可選的屬性。schema屬性,指明了這個映射所引用的表所在的schema名稱。假若指定了這個屬性,表名會加上所指定的schema的名字擴展schema的名字擴展為全限定名。假若沒有指定,表明就不會使用全限定名。default-cascade指定了未注明cascade屬性和集合類會采用什么樣的默認級聯風格。auto-import屬性默認讓我們在查詢語言中可以使用非全限定名的類名。default-access告訴我們怎么訪問屬性。
<hibernate-mapping schema="schemaName" (1) default-cascade="none|save-update" auto-import="true|false" default-access="property|field|nosetter|ClassName" assembly="assembly.name" namespace="namespace.name" >
hibernate-mapping |
||
schema(可選) | schemaName | 數據庫schema名稱。 |
default-cascade(可選-默認為none) | none|save-update | 默認的級聯風格。 |
auto-import(可選-默認為true) | true|false | 指定是否我們可以在查詢語言中使用非全限定的類名(僅限於本映射文件中的類)。 |
default-acess(可選-默認為property) | property|field|nosetter|ClassName | NHibernate訪問屬性時的策略。 |
assembly(可選) | assembly.name | 指定一個程序集,如果在映射文檔中沒有指定程序集,就使用這個程序集 |
namespace | namespace.name | 指定一個命名空間前綴,如果在一個映射文檔中沒有指定全限定名,就使用這個命名空間名。 |
class:可以使用class元素來定義一個持久化類
<class name="ClassName" table="tableName" discriminator-value="discriminator_value" mutable="true|false" schema="owner" proxy="ProxyInterface" dynamic-update="true|false" dynamic-insert="true|false" polymorphism="implicit|explicit" where="arbitrary sql where condition" persister="PersisterClass" lazy="true|false" />
class | ||
name | ClassName | 持久化類(或者接口)的全限定名 |
table | tableName | 對應的數據庫表名。 |
discriminator-value(可選-默認和類名一樣) | discriminator_value | 一個用於區分不同的子類的值,在多態行為時使用。 |
mutable(可選,默認為true) | true|false | 表明該類的實例可變(不可變)。 |
schema(可選) | owner | 覆蓋在根<hibernate-mapping>元素中指定的schema名字 |
proxy(可選) | ProxyInterface | 指定一個接口,在延遲裝載時作為代理使用。你可以在這里使用該類自己的名字 |
dynamic-update(可選,默認為false) | true|false | 指定用於UPDATE的sql將會在運行時動態生成,並且只更新哪些改變過的字段 |
dynamic-insert(可選,默認為false) | true|false | 指定用於INSERT的sql將會在運行時動態生成,並且只包含哪些非空字段 |
polymorphism(可選,默認為implicit(隱式)) | implicit|explicit | 界定是隱式還是顯式的使用查詢多態。 |
where(可選) | arbitrary sql where condition | 指定一個附加的SQL WHERE 條件,在抓取這個類的對象時會一直增加這個條件 |
persister(可選) | PersisterClass | 指定一個定制的IClassPersister。 |
lazy(可選) | true|false | 假若設置lazy=“true”,就是設置這個類自己的名字作為proxy接口的一種等價快捷方式 |
主鍵Id
<id name="propertyName" type="typename" column="column_name" unsaved-value="any|none|null|id_value" access="field|property|nosetter|ClassName"> <generator class="generatorClass"/> </id>
Id | ||
name(可選) |
propertyName | 標識屬性的名字。 |
type(可選) |
typename | 標識NHibernate類型的名字。 |
unsaved-value(可選-默認為null) | any|none|null|id_value | 一個特定的標識屬性值,用來標識該實例是剛剛創建的,尚未保存。這可以把這種實例和從以前的sssion中裝載過(可能又做過修改)但未再次持久化的實例區分開來。 |
column(可選-默認為屬性名) | column_name | 主鍵字段的名字 |
access(可選-默認為property) | field|property|nosetter|ClassName | NHibernate用來訪問屬性值的策略 |
如果name屬性不存在,會認為這個類沒有標識屬性。
unsaved-value屬性很重要!如果你的類的標識屬性不是默認為null的,你應該指定正確的默認值。特別重要的是在使用值類型System.ValueType,例如System.Int32或者System.Guid作為你的<id>屬性時確保清楚的設置這個屬性,因為System.ValueType對象不可能為null值。
還有一個另外的<composite-id>聲明可以訪問舊式的多主鍵數據。不鼓勵使用這種方式。
gennerator
<id name="Id" type="Int64" column="uid" unsaved-value="0"> <generator class="NHibernate.Id.TableHiLoGenerator"> <param name="table">uid_table</param> <param name="column">next_hi_value_column</param> </generator> </id>
必須聲明的<generator>子元素是一個.NET類的名字,用來為該持久化類的屬性生成唯一的標識。如果這個生成器實例需要某些配置值或者初始化參數,用<param>元素傳遞。
identity
|
對DB2,MySQL, MS SQL Server, Sybase和HypersonicSQL的內置標識字段提供支持。返回的標識符是 Int64, Int32 或者 Int16類型的。 |
sequence(序列) |
對DB2,MySQL, PostgreSQL, Oracle的內置標識字段提供支持。返回的標識符是Int64 Int32 或者 Int16類型的。 |
hilo(高低位) |
使用一個高/低位算法來高效的生成Int64, Int32 或者 Int16類型的標識符。給定一個表和字段(默認分別是hibernate_unique_key 和next)作為高位值得來源。高/低位算法生成的標識符只在一個特定的數據庫中是唯一的。 |
seqhilo(使用序列的高低位) |
使用一個高/低位算法來高效的生成Int64, Int32 或者 Int16類型的標識符,給定一個數據庫序列(sequence)的名字。 |
uuid.hex
|
用一個System.Guid和它的ToString(string format)方法生成字符串類型的標識符。字符串的長度取決於 format的配置。 |
uuid.string |
用一個新的System.Guid產生一個byte[] ,把它轉換成字符串。 |
guid |
用一個新的System.Guid 作為標識符。 |
guid.comb |
用Jimmy Nilsson在文章http://www.informit.com/articles/article.asp?p=25862中描述的算法產生一個新的System.Guid。 |
native(本地) |
根據底層數據庫的能力選擇 identity, sequence 或者 hilo中的一個。 |
assigned(程序設置) |
讓應用程序在save()之前為對象分配一個標示符。 |
foreign(外部引用) |
使用另外一個相關聯的對象的標識符。和<one-to-one>聯合一起使用。 |
聯合ID(composite-id)
<composite-id name="propertyName"class="ClassName" unsaved-value="any|none" access="field|property|nosetter|ClassName"> <key-property name="propertyName" type="typename" column="column_name"/> <key-many-to-one name="propertyName class="ClassName" column="column_name"/> ...... </composite-id>
如果表使用聯合主鍵,你可以把類的多個屬性組合成為標識符屬性。<composite-id>元素接受<key-property>屬性映射和<key-many-to-one>屬性映射作為子元素。
<composite-id> <key-property name="medicareNumber"/> <key-property name="dependent"/> </composite-id>
你的持久化類必須重載Equals()和HashCode()方法,來實現組合的標識符判斷等價.也必須實現Serializable接口
不幸的是,這種組合關鍵字的方法意味着一個持久化類是它自己的標識。除了對象自己之外,沒有什么方便的“把手”可用。你必須自己初始化持久化類的實例,在使用組合關鍵字Load()持久化狀態之前,必須填充他的聯合屬性。我們會在TODO: LINKTOCOMPENENTS 中說明一種更加方便的方法,把聯合標識實現為一個獨立的類,下面描述的屬性只對這種備用方法有效:
name (可選) |
一個組件類型,持有聯合標識 |
class (可選 - 默認為通過反射(reflection)得到的屬性類型) |
作為聯合標識的組件類名。 |
unsaved-value (可選 - 默認為 none) |
假如被設置為any的值,就表示新創建,尚未被持久化的實例將持有的值。 |
識別器(discriminator)
<discriminator column="discriminator_column" type="discriminator_type" force="true|false" insert="true|false" />
column (可選 - 默為 class) |
識別器字段的名字 |
type (可選 - 默認為 String) |
一個NHibernate字段類型的名字 |
force (可選 - 默認為 false) |
強制"NHibernate指定允許的識別器值,就算取得的所有實例都是根類的。 |
insert (可選 - 默認為 true) |
當識別器是被映射的組件的標識符的一部分時設置為false。 |
標識器字段的實際值是根據<class> 和<subclass>元素的discriminator-value得來的。
文章來源:http://www.cnblogs.com/wolf-sun/p/4138918.html