標籤:style blog class code c java
系列文章
[Nhibernate]體繫結構
[NHibernate]ISessionFactory配置
[NHibernate]持久化類(Persistent Classes)
[NHibernate]O/R Mapping基礎
[NHibernate]集合類(Collections)映射
[NHibernate]關聯映射
[NHibernate]Parent/Child
[NHibernate]緩衝(NHibernate.Caches)
什麼是NHibernate.Mapping.Attributes?
NHibernate.Mapping.Attributes是NHibernate的附加軟體,它是Pierre Henri Kuat(aka KPixel)貢獻的;以前的實現者是John Morris.NHibernate需要映射資訊來綁定你的域對象到資料庫。通常他們被寫在(並且被儲存在)分散的hbm.xml檔案裡。
使用NHibernate.Mapping.Attributes,你可以使用.NET屬性(attributes)來修飾你的實體和被用於產生.hbm.xml映射(檔案或者流)的屬性(attributes).因此,你將不再會為這些令人煙霧的檔案而煩惱。
這個庫裡面的內容包括:
- NHibernate.Mapping.Attributes:你需要的唯一工程(作為終端使用者)。
- Test一個使用屬性(attributes)和HbmSerializer的簡單用例,是NUnit的TestFixture。
- Genaerator:用來產生屬性(attributes)和HbmWriter的程式。
- Refly:感謝Jonathan de Halleux提供這個庫,它使的產生代碼變得如此簡單。
重要提示
這個庫是使用檔案/src/NHibernate.Mapping.Attributes/nhibernate-mapping-2.0.xsd(它嵌入在程式集中能檢查產生的xml流的合法性)產生的,這個檔案可能在NHibernate每次發布新版本時發生變化,所以你應該在不同的版本中使用它時,重建它(開啟Generator工程,編譯並且運行Generator項目)。但是,在0.8之前的版本中它並沒有通過測試。
如何使用?
終端使用者類 是NHibernate.Mapping.Attributes.HbmSerializer.這個類序列化你的領域模型到映射流.你可以逐個序列化程式集中的類.NHibernate.Mapping.Attributes.Test可以作為參考.
第一步用屬性(attributes)修飾你的實體;你可以用 [Class], [Subclass], [JoinedSubclass]或者[Component].然後,修飾成員(欄位/屬性properties);它們能夠代替很多映射中需要使用的屬性(attributes ),例如:
1 [NHibernate.Mapping.Attributes.Class]2 public class Example3 {4 [NHibernate.Mapping.Attributes.Property]5 public string Name;6 }
完成這個步驟後,使用NHibernate.Mapping.Attributes.HbmSerializer:(這裡我們使用了Default ,它是一個執行個體,在你不必須/不想自己建立它時使用).
1 System.IO.MemoryStream stream = new System.IO.MemoryStream(); // where the xml will be written 2 NHibernate.Mapping.Attributes.HbmSerializer.Default.Validate = true; // Enable validation (可選) 3 // Here, we serialize all decorated classes (but you can also do it class by class) 4 NHibernate.Mapping.Attributes.HbmSerializer.Default.Serialize( 5 stream, System.Reflection.Assembly.GetExecutingAssembly() ); 6 stream.Position = 0; // Rewind 7 NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration(); 8 cfg.Configure(); 9 cfg.AddInputStream(stream); // Use the stream here10 stream.Close();11 // Now you can use this configuration to build your SessionFactory...
注意:正如你所見:NHibernate.Mapping.Attributes是沒有(真正的)侵入性的.在你的對象上設定屬性(attributes ),不會強迫你在NHibernate 使用它們,並且不會破壞你的架構體系中的任何約束.屬性(Attributes)僅僅是純粹的資訊.
提示
- 使用HbmSerializer.Validate來啟用/禁用產生的xml流的合法性檢查(依靠NHibernate mapping schema);對於快速尋找問題這是很有用的(它們被StringBuilder寫入HbmSerializer.Error).如果錯誤是這個庫預期的,庫會看它是否是已知的問題並且報告它;解決這些問題能協助你完成你的解決方案. :)
- 你的類,欄位和屬性properties(成員)可以是私人的;請確認你有使用反射訪問私人成員的許可權(ReflectionPermissionFlag.MemberAccess).
- 映射類的成員也會在基類中尋找(直到找到映射的基類).因此,你可以在基類(沒有做映射)中修飾成員,然後在它的(做過映射的)子類中使用它.
- 對於一個有類型(System.Type)的Name,使用Name="xxx"(作為string)設定類型或者設定NameType=typeof(xxx);(給 "Name"添加"類型")
- 預設情況下,.NET屬性(attributes)沒有維持屬性(attributes)的順序;因此,你必須自己設定順序,在你管理順序的時候(使用每個屬性的第一個參數).強烈推薦設定它,當你的一個成員上有超過一個屬性(attribute )時.
- 只要不產生含糊,你可以在成員上定義很多不相干的屬性(attributes).一個好的例子是在標識符成員上的類描述(class-related)屬性(attributes )(類似鑒別器<discriminator>).但是不要忘記管理順序(<discriminator> 必須在<id>的後面).順序來自NHibernate mapping schema中元素(elements)的順序.在我個人看來,我更喜歡在屬性上使用負數(如果它們是在前面的!).
- 你可以在類上面加 [HibernateMapping] 來指定<hibernate-mapping> 屬性(attributes)(當類被序列化成流時使用).你也可以使用HbmSerializer.Hbm*屬性(properties)(當被[HibernateMapping]修飾的類型或程式集被序列化時被使用).
- 不使用一個字串作為鑒別器值(DiscriminatorValue)(在[Class]和[Subclass]),你可以在任何你需要的對象上這樣使用.例子: [Subclass(DiscriminatorValueEnumFormat="d", DiscriminatorValueObject=DiscEnum.Val1)]
在這裡,對象是一個枚舉,你可以設定你需要的格式(預設的值是"g").注意你必須把它放在前面!對於其他的類型,只是簡單的使用了對象的ToString()方法.
- 如果你使用Nullables.NullableXXX類型的的成員(在庫Nullables中),系統會自動對應到Nullables.NHibernate.NullableXXXType;不用在[Property]中設定Type="..."(讓它為空白).感謝Michael Third的這個主意. :)
- NHibernate.Mapping.Attributes產生的每個流都有一個產生日期的注釋;你可以通過方法WriteDateComment啟用/禁用它.
- 如果你忘記提供一個必須的xml屬性(attribute),系統會拋出一個異常,在建立映射時.
- 映射[Component] 時,被推薦的並且最簡單的方式是使用[ComponentProperty].
首先,放置[Component]在組件類並且映射它的欄位/屬性.注意不要在[Component]設定名字.然後,在你的類的每個成員,添加[ComponentProperty].但是你不能改變每個成員的存取(Access),更新(Update)或插入(Insert).
在NHibernate.Mapping.Attributes.Test裡有一個例子(注意CompAddress類和他在其他類中的使用).
注意最後一件事情:ComponentPropertyAttribute是從DynamicComponentAttribute繼承來的,容易把它緊接著寫在 <component>元素的後面,在XML流中.
- 另一個映射[Component]的方式是,它用這種方法讓庫工作:如果一個類包含了一個組件映射,那麼這個組件將會被類包含.NHibernate.Mapping.Attributes.Test包含JoinedBaz和Stuff使用地址(Address)組件的例子. 很簡單的,添加了以後 [Component(Name = "MyComp")] private class SubComp : Comp {}
- 在所有類中,一個優勢是能夠改變每個成員的存取(Access),更新(Update)或插入(Insert).但是,你必須添加組件子類到每個類中(並且它不能被繼承).
- 關於自訂。HbmSerializer使用HbmWriter序列化各種屬性(attributes)。他的方法是虛的;因此你可以建立一個子類,重寫任何方法(來改變它的預設行為)。
使用屬性(property)HbmSerializer.HbmWriter來改變寫的實現者。(你可以設定一個HbmWriter的子類)。使用了部分提示的例子:(0,1和2按順序排列)
1 [NHibernate.Mapping.Attributes.Id(0, TypeType=typeof(int))] // Don‘t put it after [ManyToOne] !!!2 [NHibernate.Mapping.Attributes.Generator(1, Class="uuid.hex")]3 [NHibernate.Mapping.Attributes.ManyToOne(2, ClassType=typeof(Foo), OuterJoin=OuterJoinStrategy.True)]4 private Foo Entity;
產生的:
1 <id type="Int32">2 <generator class="uuid.hex" />3 </id>4 <many-to-one name="Entity" class="Namespaces.Foo, SampleAssembly" outer-join="true" />
已知的問題和TODOs
首先,閱讀原始碼裡面的TODOs
Position屬性(property)被加在所有屬性(attributes)上,用來給他們排序。但是仍然有問題:
當一個父元素"p"有一個子項目"x",它的另一個子項目"c"有子項目"x"。:D 如
1 <p>2 <c>3 <x />4 </c>5 <x />6 </p>
在這個例子中,如果這樣寫:
1 [Attributes.P(0)]2 [Attributes.C(1)]3 [Attributes.X(2)]4 [Attributes.X(3)]5 public MyType MyProperty;
X(3)將會屬於C(1)!(和X(2)一樣)
下面是<dynamic-component>和<nested-composite-element>的情況。
另一個壞訊息是,現在,後來加入的XML元素不能被包含.例如:沒有辦法在<dynamic-component>放置集合.原因是nhibernate-mapping-2.0.xsd檔案告訴程式元素怎麼被建立,按照什麼順序被建立,並且NHibernate.Mapping.Attributes按這個順序使用它們.
總之,解決方案應該添加整型的ParentNode屬性(property)給BaseAttribute,這樣你能夠建立一個真實的情況...
實際上,沒有其他的知識點了而且也沒有計劃好的修改.這個庫將會成為穩定的完整版本;但是你發現了問題或者有有效改進想法,請聯絡我們!
另一個訊息,希望有比NHibernate.Mapping.Attributes.Test更好的TestFixture.:D
開發人員須知
schema (nhibernate-mapping-2.0.xsd)的任何改變意味著:
- 檢查是否要在Generator中做任何改變(象updating KnowEnums / AllowMultipleValue / IsRoot / IsSystemType / IsSystemEnum / CanContainItself)
- 更新/src/NHibernate.Mapping.Attributes/nhibernate-mapping-2.0.xsd (複製/粘貼),並且再次運行Generator(即使你沒有修改)
- 運行測試專案,確定沒有已知的異常拋出.應該在可以確保能夠把握改變帶來的破壞時,修改/添加這個項目中一個類/屬性(property)(=>更新hbm.xml檔案和/或NHibernate.Mapping.Attributes-1.1.csproj項目的引用)
這個實現基於NHibernate mapping schema;有可能很多"標準schema特性"沒有被支援...
這個版本的NHibernate.Mapping.Attributes需要使用NHibernate庫的版本的schema來產生.
這個項目的設計,效能是一個(十分)小的目標,實現和維護則要重要許多.
本文來自《NHibernate 中文文檔》