六、鑒别器
在"一棵對象繼承樹對應一個表"的政策中,<discriminator>元素是必需的, 它定義了表的鑒别器字段。
鑒别器字段包含标志值,用于告知持久化層應該為某個特定的行建立哪一個子類的執行個體。 如下這些受到限制的類型可以使用: String, Char, Int32,Byte, Short, Boolean , YesNo, TrueFalse。
(1)
column (可選 - 預設為 class) 鑒别器字段的名字
(2)
type (可選 - 預設為 String) 一個NHibernate字段類型的名字。
(3)
force(強制) (可選 - 預設為 false)
"強制"NHibernate指定允許的鑒别器值,即使當取得的所有執行個體都是根類的。
(4)
insert (可選 - 預設為true)
如果你的鑒别器字段也是映射為複合辨別(composite identifier)的一部分, 則需将 這個值設為false。
(5)
formula (可選)
一個SQL表達式,在類型判斷(判斷是父類還是具體子類-譯注)時執行。可用于基于内容的鑒别器。
鑒别器字段的實際值是根據discriminator-value 和<class> and <subclass>元素中 的discriminator-value屬性得來的。
force屬性僅僅在這種情況下有用的:表中包含沒有被映射到持久化類的附加辨識器值。
這種情況不會經常遇到。
使用formula屬性你可以定義一個SQL表達式,用來判斷一個行資料的類型。
<version>元素是可選的,表明表中包含附帶版本資訊的資料。
這在你準備使用 長事務(long
transactions)的時候特别有用。
說明:
column (可選 - 預設為屬性名): 指定持有版本号的字段名。
name 持久化類的屬性名。
type (可選 - 預設是 Int32): 版本号的類型。
access (可選 - 預設是 property):
NHibernate用于通路屬性值的政策。
unsaved-value(可選 - 預設是undefined):
用于标明某個執行個體時剛剛被執行個體化的(尚未儲存)版本屬性值, 依靠這個值就可以把這種情況
和已經在先前的session中儲存或裝載的脫管(detached)執行個體區分開來。 (undefined指明應被使用的辨別屬性值。)
(6)
generated(可選 - 預設是 never): 表明此版本屬性值是否實際上是由資料庫生成的。 請參閱 部分的讨論。
版本号必須是以下類型:Int64, Int32, Int16, Ticks,或者 Timestamp, TimeSpan。
可選的<timestamp>元素指明了表中包含時間戳資料。 這用來作為版本的替代。
時間戳本質上是一種對樂觀鎖定的一種不是特别安全的實作。當然, 有時候應用程式可能在其他方面使用時間戳。
說明:
column(可選 - 預設為屬性名): 持有時間戳的字段名。
name: 在持久化類中的.NE風格的屬性名, 其.NE類型是 DateTime的。
access (可選 - 預設是 property): NHibernate用于通路屬性值的政策。
unsaved-value (可選 - 預設是null):
用于标明某個執行個體時剛剛被執行個體化的(尚未儲存)版本屬性值, 依靠這個值就可以把這種情況和
已經在先前的session中儲存或裝載的脫管(detached)執行個體區分開來。 (undefined 指明使用辨別屬性值進行這種判斷。)
generated : 指出時間戳值是否實際上是由資料庫生成的.請參閱的讨論。
注意<timestamp>等價于 <version type="timestamp">。
<property>元素為類定義了一個持久化類的屬性。
name: 屬性的名字。
column (可選 - 預設為屬性名字): 對應的資料庫字段名。
type (可選): 一個NHibernate類型的名字。
update, insert (可選 - 預設為 true)
: 表明用于UPDATE 和/或 INSERT 的SQL語句中是否包含這個被映射了的字段。 這二者如果都設定為false
則表明這是一個“外源性(derived)”的屬性, 它的值來源于映射到同一個(或多個)
字段的某些其他屬性,或者通過一個trigger(觸發器)或其他程式生成。
formula (可選): 一個SQL表達式,定義了這個計算 (computed)
屬性的值。計算屬性沒有和它對應的資料庫字段。
access (可選 - 預設值為 property):
NHibernate用來通路屬性值的政策。
(7)
optimistic-lock (可選 - 預設為 true):
指定這個屬性在做更新時是否需要獲得樂觀鎖定(optimistic lock)。
換句話說,它決定這個屬性發生髒資料時版本(version)的值是否增長。
(8)
generated (可選 - 預設為 never):
表明此屬性值是否實際上是由資料庫生成的。 請參閱的讨論。
typename可以是如下幾種
NHibernate基本類型名(比如:Int32, String, Char, DateTime,
Timestamp, Single, Byte[], Object, ...)。
一個.Net類的名字,這個類屬于一種預設基礎類型 (比如: System.Int16,
System.Single, System.Char, System.String, System.DateTime, System.Byte[],
...)。
一個枚舉類型的名字。(比如:. eg.Color)。
一個可以序列化的.NET類的名字。
一個自定義類型的類的名字。(比如: Illflow.Type.MyCustomType)。
注意你必須為所有類型(除了NHibernate基礎類型)指定完整的應用程式集權限定名 (或者是在<hibernate-mapping>裡面配置了assembly和namespace屬性)。
NHibernate支援.NET 2.0的可空類型,這些類型和對應的非可空類型處理方式是一緻的, 例如:Nullable<Int32>可以對應type="Int32"或者是type="System.Int32"。
如果你沒有指定類型,NHibernate會使用反射來得到這個名字的屬性,
以此來猜測正确的NHibernate類型。NHibernate會對屬性讀取器(getter方法)的傳回類進行解釋, 按照規則2,3,4的順序。然而,這并不足夠。
在某些情況下你仍然需要type屬性。 (比如,為了差別NHibernateUtil.DateTime和NHibernateUtil.Timestamp,或者為了指定一個自定義類型。)
access屬性用來讓你控制NHibernate如何在運作時通路屬性。 在預設情況下,
NHibernate會按照access-strategy.naming-strategy來格式化屬性名 .naming-strategy不是必填項。
表 5.1. 通路政策
<col>
通路政策名
描述
property
預設實作:NHibernate通路類的set/get屬性,這種方式沒有命名政策,因為name就代表屬性的名稱。
field
NHibernate将會直接通路成員變量。NHibernate使用name作為成員變量的名稱。
當對象屬性的get和set裡面有額外的操作,而你不想讓NHibernate設定或者讀取對象時執行額外的操作,
可以用這個政策。當你使用HQL時需要屬性名而非字段時,就需要命名政策(Naming Strateg)。
nosetter
NHibernate将會在設定值時直接通路字段,獲得值時通路屬性。 當API使用者不能直接改變值,因而隻為屬性隻提供了get通路器時,
你可以用這個政策。NHibernate使用name屬性(attribute)作為屬性(Property ),
并且需要提供字段名,是以命名政策必須(Naming Strategy)使用。
ClassName
如果NHibernate内置的通路政策(Access Strategie)不能滿足你的要求。
你可以通過實作NHibernate.Property.IPropertyAccessor接口來自己的通路政策(Access Strategie)。
這個值需要用程式集名(Assembly)來限定,這樣就能通過 Activator.CreateInstance(string
AssemblyQualifiedName)來讀取。
命名政策(Naming Strategy)
命名政策
camelcase
name屬性被轉換CamelCase格式來查找字段。<property name="Foo"
... >使用foo字段。
camelcase-underscore
name屬性被轉換CamelCase格式并添加下劃線字首來查找字段。<property
name="Foo" ... >使用_foo字段。
lowercase
name屬性被轉換小寫格式來查找字段。<property name="FooBar" ...
> 使用 foobar字段.
lowercase-underscore
name屬性被轉換小寫格式并添加下劃線字首來查找字段。<property
name="FooBar" ... >使用_foobar字段.
pascalcase-underscore
name屬性添加下劃線字首來查找字段。<property name="Foo" ...
>使用_Foo字段。
pascalcase-m
name屬性添加字母m字首來查找字段。<property name="Foo" ...
>使用mFoo字段。
pascalcase-m-underscore
name屬性添加字母m和下劃線字首來查找字段。<property name="Foo" ...
> 使用m_Foo字段。
通過 many-to-one元素,可以定義一種常見的與另一個持久化類的關聯。這種關系模型是多對一關聯。(實際上是一個對象引用。)
name:屬性名。
column資料庫字段名
class(可選 - 預設是通過反射得到屬性類型): 關聯的類的名字。
cascade(級聯) (可選): 指明哪些操作會從父對象級聯到關聯的對象。
fetch (可選 - 預設為 select):
在外連接配接抓取(outer-join fetching)和序列選擇抓取(sequential select fetching)兩者中選擇其一。
(可選 - defaults to true) 指定對應的字段是否包含在用于UPDATE 和/或 INSERT
的SQL語句中。如果二者都是false,則這是一個純粹的 “外源性(derived)”關聯,它的值是通過映射到同一個(或多個)字段的某些其他屬性得到
或者通過trigger(觸發器)、或其他程式。
property-ref: (可選) 指定關聯類的一個屬性,這個屬性将會和本外鍵相對應。
如果沒有指定,會使用對方關聯類的主鍵。
access(可選 - 預設是 property):
NHibernate用來通路屬性的政策。
(9)
unique (可選): 使用DDL為外鍵字段生成一個唯一限制。此外,
這也可以用作property-ref的目标屬性。這使關聯同時具有 一對一的效果。
(10)
optimistic-lock (可選 - 預設為 true):
(11)
not-found (可選 - 預設為 exception):
指定外鍵引用的資料不存在時如何處理: ignore會将資料不存在作為關聯到一個空對象(null)處理。
cascade屬性允許下列值:: all, save-update, delete, none.
設定除了none以外的其它值會傳播特定的操作到關聯的(子)對象中。參見後面的“Lifecycle Objects(自動管理生命周期的對象)”。
fetch參數允許下列兩個不同值:
join外連接配接抓取
select使用隔離查詢抓取
一個典型的簡單many-to-one 定義例子:
property-ref屬性隻應該用來對付老舊的資料庫系統,
可能有外鍵指向對方關聯表的是個非主鍵字段(但是應該是一個惟一關鍵字)的情況下。 這是一種十分醜陋的關系模型。比如說,假設Product類有一個惟一的序列号,
它并不是主鍵。(unique屬性控制NHibernate通過SchemaExport工具生成DDL的過程。)
那麼關于OrderItem 的映射可能是:
當然,我們決不鼓勵這種用法。
持久化對象之間一對一的關聯關系是通過 one-to-one元素定義的。
class (可選 - 預設是通過反射得到的屬性類型):被關聯的類的名字。
cascade(級聯) (可選) 表明操作是否從父對象級聯到被關聯的對象。
constrained(限制) (可選)
表明該類對應的表對應的資料庫表,和被關聯的對象所對應的資料庫表之間,通過一個外鍵引用對主鍵進行限制。
這個選項影響Save()和Delete()在級聯執行時的先後順序以及 決定該關聯能否被委托(也在schema export
tool中被使用).
fetch (可選 - 預設設定為select):
在外連接配接抓取或者序列選擇抓取選擇其一.
property-ref: (可選)
指定關聯類的屬性名,這個屬性将會和本類的主鍵相對應。如果沒有指定,會使用對方關聯類的主鍵。
有兩種不同的一對一關聯:
主鍵關聯
惟一外鍵關聯
主鍵關聯不需要額外的表字段;如果兩行是通過這種一對一關系相關聯的,那麼這兩行就共享同樣的主關鍵字值。是以如果你希望兩個對象通過主鍵一對一關聯,你必須确認它們被賦予同樣的辨別值!
比如說,對下面的Employee和Person進行主鍵一對一關聯:
現在我們必須確定PERSON和EMPLOYEE中相關的字段是相等的。我們使用一個被成為foreign的特殊的現在我們必須確定PERSON和EMPLOYEE中相關的字段是相等的。我們使用一個被成為foreign的特殊的hibernate辨別符生成政策:辨別符生成政策: foreign:
一個剛剛儲存的Person執行個體被賦予和該Person的employee屬性所指向的Employee執行個體同樣的關鍵字值。
另一種方式是一個外鍵和一個惟一關鍵字對應,上面的Employee和Person的例子,如果使用這種關聯方式,可以表達成:
如果在Person的映射加入下面幾句,這種關聯就是雙向的: