前言
現代化大型項目通常使用獨立的數據庫來存儲數據,其中以采用關系型數據庫居多。用于開發項目的高級語言(c#、java等)是面向對象的,而關系型數據庫是基于關系的,兩者之間的溝通需要一種轉換,也就是對象/關系數據庫映射(object/relational mapping,簡稱orm)。
c#可用以解決對象/關系數據庫映射的工具有多種,常見的有ef (entity framework)、nhibernate、ibatis等,各自的優缺點及適用場景在此不做討論,本文只對如何使用nhibernate做個總結。
nhibernate是一個面向.net環境的對象/關系數據庫映射工具。
1. 創建項目文件
在visual studio開發工具里創建需要的項目結構。
2. 添加對nhibernate的引用
當下載并解壓nhibernate安裝包后,電腦上就會創建一些目錄,包括“required_bins”,要把 required_bins目錄下的dll引用到項目里來,它們是nhibernate使用的核心組件。
nhibernate.dll(基礎類庫,與數據庫直接打交道,位于數據訪問層)
iesi.collections(基礎類庫輔助類庫,位于數據訪問層)
antlr3.runtime(基礎類庫輔助類庫,位于數據訪問層)
nhibernate.bytecode.spring.dll(proxy factory類庫,用于打開/關閉nhibernate session,位于數據訪問層工具類庫)
圖1 添加對nhibernate的引用
3. 配置nhibernate
文件:hibernate.cfg.xml,位于站點根目錄。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<? xml version = "1.0" encoding = "utf-8" ?> < hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2" > < session-factory > < property name = "connection.driver_class" >nhibernate.driver.sqlclientdriver</ property > < property name = "connection.connection_string" > data source=120.120.200.200;initial catalog=mamall;persist security info=true;user id=mamall;password=mima123;connection reset=false;connection lifetime=50;min pool size=1;max pool size=500 </ property > < property name = "adonet.batch_size" >10</ property > < property name = "show_sql" >true</ property > < property name = "dialect" >nhibernate.dialect.mssql2005dialect</ property > < property name = "command_timeout" >10</ property > < property name = "query.substitutions" >true 1, false 0, yes 'y', no 'n'</ property > < property name = "proxyfactory.factory_class" > nhibernate.bytecode.spring.proxyfactoryfactory,nhibernate.bytecode.spring</ property > < property name = "connection.release_mode" >on_close</ property > < mapping assembly = "fuli.entity" /> </ session-factory > </ hibernate-configuration > |
4. 編寫nhibernatehelper輔助類
文件:nhibernatehelper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
using system; using fuli.tool.log; using nhibernate; using nhibernate.cfg; namespace fuli.dal.common { public class nhibernatehelper { private static isessionfactory _sessionfactory; private static isessionfactory sessionfactory { get { if (_sessionfactory == null ) { var configuration = new configuration(); configuration.configure(); _sessionfactory = configuration.buildsessionfactory(); } return _sessionfactory; } } public static isession opensession() { try { return sessionfactory.opensession(); } catch (exception ex) { loghelper.getinstance().writemessage( "打開數據庫失敗,錯誤:" + ex.tostring()); return null ; } } } } |
5. 創建數據模型
nhibernate允許直接使用plain old clr objects (pocos),而不用通過存儲過程來直接和數據庫交互。使用pocos的一個優勢在于不用綁定特定的持久化層。相比較而言,有些orm解決方案需要特殊屬性,或者是基于模型對象,這些對象又是從特定的基類中繼承而來的。
在nhibernate中不用特殊的修飾就可以讓對象和持久化層交互。要注意的是所有需要持久化的屬性必須是虛擬的,并且要開啟延遲加載,所有數據模型類中的公共方法必須是虛擬的,哪怕它們并沒有包含到映射文件中。
通常來講,最好把所有的屬性都設置為虛擬的。
可以借助mygeneration自動代碼工具從數據表生成數據模型和對應的映射文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
using system; using system.collections.generic; namespace fuli.entity.domain { /// <summary> /// 共享編碼表(字典表) /// </summary> [serializable] public class sharedcode { #region 構造方法 public sharedcode() { m_id = 0; m_category = string .empty; m_text = string .empty; m_value = string .empty; m_isdefault = false ; m_description = string .empty; m_parentid = 0; m_sortorder = 0; } #endregion 構造方法 #region 私有變量 private long m_id; private string m_category; private string m_text; private string m_value; private bool m_isdefault; private string m_description; private long m_parentid; private short m_sortorder; #endregion 私有變量 #region 公有屬性 ///<summary> /// 主鍵id ///</summary> public virtual long id { get { return m_id; } set { m_id = value; } } ///<summary> /// 分類 ///</summary> public virtual string category { get { return m_category; } set { m_category = value; } } ///<summary> /// 文本 ///</summary> public virtual string text { get { return m_text; } set { m_text = value; } } ///<summary> /// 編碼值 ///</summary> public virtual string value { get { return m_value; } set { m_value = value; } } ///<summary> /// 是否是同類里默認 ///</summary> public virtual bool isdefault { get { return m_isdefault; } set { m_isdefault = value; } } ///<summary> /// 描述 ///</summary> public virtual string description { get { return m_description; } set { m_description = value; } } ///<summary> /// 父級id(如果有) ///</summary> public virtual long parentid { get { return m_parentid; } set { m_parentid = value; } } ///<summary> /// 排列次序 ///</summary> public virtual short sortorder { get { return m_sortorder; } set { m_sortorder = value; } } #endregion 公有屬性 #region 擴展屬性 #endregion 擴展屬性 #region rewrite equals and hashcode /// <summary> /// /// </summary> public override bool equals( object obj) { if ( this == obj) return true ; if ((obj == null ) || (obj.gettype() != gettype())) return false ; sharedcode castobj = (sharedcode)obj; return (castobj != null ) && (m_id == castobj.id); } /// <summary> /// 用唯一值實現gethashcode /// </summary> public override int gethashcode() { int hash = 57; hash = 27 * hash * m_id.gethashcode(); return hash; } #endregion rewrite equals and hashcode } } |
6. 創建nhibernate映射文件
nhibernate使用xml映射文件來映射poco到數據庫對象。雖然在很多案例中這可能是一對一關系,但這并不是必定的。
文件:sharedcode.hbm.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<? xml version = "1.0" encoding = "utf-8" ?> < hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" > < class name = "fuli.entity.domain.sharedcode, fuli.entity" table = "sharedcode" > < id name = "id" column = "id" type = "int64" unsaved-value = "0" > < generator class = "native" /> </ id > < property name = "category" type = "string" column = "category" /> < property name = "text" type = "string" column = "text" /> < property name = "value" type = "string" column = "value" /> < property name = "isdefault" type = "boolean" column = "isdefault" /> < property name = "description" type = "string" column = "description" /> < property name = "parentid" type = "int64" column = "parentid" /> < property name = "sortorder" type = "int16" column = "sortorder" /> </ class > </ hibernate-mapping > |
在hibernate-maping標簽中,同時引用類集(pocos)所屬的程序集命名空間。
- class元素表示到單個poco的映射。name表示上面的程序集和命名空間中的類名,table屬性告訴nhibernate數據庫中的哪個表或者視圖將被映射。
- id元素告訴nhibernate哪個數據庫的字段和對應的對象作為一個唯一鍵來使用。在本例中,我們使用id這個字段。
- generator元素告訴nhibernate怎樣給新實體來創建唯一id。
- property標簽是見得最多的標簽。它簡單地映射一個到數據表或者視圖中對應字段的映射。
一旦xml文件創建好了,需要更改xml的生成方式確保它被設置為嵌入式資源,否則nhibernate不會讀取這個xml文件,那么映射就不會生效了。
圖2 映射文件必須是嵌入的資源
7. 使用 nhibernate連接數據庫
文件:commonrepository
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
namespace fuli.dal.sqlserverimpl { public class commonrepository : icommonrepository { #region 新增 /// <summary> /// 新增實體表 /// </summary> /// <param name="obj"></param> /// <returns></returns> public long addnewentity<t>( object obj, string tablename) where t : new () { long id = 0; try { using (isession session = nhibernatehelper.opensession()) { id = long .parse(session.save((t)obj).tostring()); session.flush(); } } catch (exception ex) { loghelper.getinstance().writemessage(tablename + operationtype.comma + ex.tostring()); } return id; } /// <summary> /// 新增實體表 /// </summary> /// <param name="entity"></param> /// <returns></returns> public treturn addnewentity<tentity, treturn>( object entity, string tablename) where tentity : new () { treturn returnvalue = default (treturn); try { using (isession session = nhibernatehelper.opensession()) { object returnobject = session.save(entity); if (returnobject != null ) { returnvalue = (treturn)convert.changetype(returnobject, typeof (treturn)); } session.flush(); } } catch (exception ex) { loghelper.getinstance().writemessage(tablename + operationtype.comma + ex.tostring()); } return returnvalue; } #endregion 新增 } } |
對于不同的實體,可以一對一地寫一個<entity>repository,專注負責相對應的實體操作。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:http://www.cnblogs.com/ywqu/p/8664360.html