自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

NHibernate2.1新特性之Tuplizers

開發(fā) 后端
本文通過一段從NHibernate源碼中摘取一個典型的例子來說明Tuplizer的用法。

Tuplizers?這個單詞在英文字典里沒有解釋,和元組(tuple)這個單詞有點相似,在NHibernate中應該翻譯為元組片斷,Tuplizers只在映射中提供,所以叫元組片段映射比較合適。

我們平時一般使用Domain Entity,然后使用< class>來映射,對Domain Entity操作。在NHibernate中,對于Domain Entity的Entity Mode為POCO類型,這時對應的tuplizer知道通過其構造方法來創(chuàng)建一個POCO,再通過其屬性訪問器來訪問POCO屬性。

Tuplizers,其完整命名空間是NHibernate.Tuple.Tuplizer,它就是根據(jù)給定的NHibernate.EntityMode,來復現(xiàn)片斷數(shù)據(jù)。如果給定的片斷數(shù)據(jù)被認為其是一種數(shù)據(jù)結構,"tuplizer"就是一個知道如何創(chuàng)建這樣的數(shù)據(jù)結構,以及如何給這個數(shù)據(jù)結構賦值的東西。

在NHibernate中有NHibernate.Tuple.Entity.IEntityTuplizer和NHibernate.Tuple.Component.IComponentTuplizer兩個接口,IEntityTuplizer負責管理上面提到的實體的契約,而IComponentTuplizer則是針對組件的。

下面從NHibernate源碼中摘取一個典型的例子來說明Tuplizer的用法。

典型實例

我想映射一個接口,對這個接口按照POCO實體模型進行持久化操作。首先想到應該可以New出來這個接口,使用工廠可以產(chǎn)生出來。在初始化這個接口的時候要重寫一些NHibernate默認的POCO行為,在對這個接口賦值的時候攔截一些操作,記錄下這個接口。獲取接口時候同樣也需要攔截。

1.Domain

  1. public interface IUser  
  2. {  
  3.     int Id { get; set; }  
  4.     string Name { get; set; }  
  5. }  

我們需要映射這個接口,但是NHibernate只會去映射類,我們怎么去改寫代碼讓NHibernate可以像類那樣去映射接口呢?這就是Tuplizers的功能。

2.代理標記proxy marker

由于這里是特殊需要,我對其這個代理做個標記,如果某個實體可以轉換為這個代理標記接口就說明是我重寫定義的Domain,

  1. /// < summary>  
  2. /// 代理標記  
  3. /// 對象實例是代理的一個實例  
  4. /// < /summary>  
  5. public interface IProxyMarker  
  6. {  
  7.     DataProxyHandler DataHandler { get; }  


3.DataProxy

利用Castle的攔截器IInterceptor接口對這個代理數(shù)據(jù)進行攔截,例如在獲取這個代理數(shù)據(jù)的時候,讓NHibernate按照POCO那樣去把其數(shù)據(jù)保存到一個字典中。

  1. /// < summary>  
  2. /// 利用Castle的攔截器,代理數(shù)據(jù)DataProxy  
  3. /// < /summary>  
  4. public sealed class DataProxyHandler:IInterceptor  
  5. {  
  6.     private readonly Dictionary< stringobject> data = new Dictionary< stringobject>(50);  
  7.     private readonly string entityName;  
  8.  
  9.     public DataProxyHandler(string entityName, object id)  
  10.     {  
  11.         this.entityName = entityName;  
  12.         data["Id"] = id;  
  13.     }  
  14.  
  15.     public string EntityName  
  16.     {  
  17.         get { return entityName; }  
  18.     }  
  19.  
  20.     public IDictionary< stringobject> Data  
  21.     {  
  22.         get { return data; }  
  23.     }  
  24.  
  25.     public void Intercept(IInvocation invocation)  
  26.     {  
  27.         invocation.ReturnValue = null;  
  28.         string methodName = invocation.Method.Name;  
  29.  
  30.         if ("get_DataHandler".Equals(methodName))  
  31.         {  
  32.             invocation.ReturnValue = this;  
  33.         }  
  34.         else if (methodName.StartsWith("set_"))  
  35.         {  
  36.             string propertyName = methodName.Substring(4);  
  37.             data[propertyName] = invocation.Arguments[0];  
  38.         }  
  39.         else if (methodName.StartsWith("get_"))  
  40.         {  
  41.             string propertyName = methodName.Substring(4);  
  42.             object value;  
  43.             data.TryGetValue(propertyName, out value);  
  44.             invocation.ReturnValue = value;  
  45.         }  
  46.         else if ("ToString".Equals(methodName))  
  47.         {  
  48.             invocation.ReturnValue = EntityName + "#" + data["Id"];  
  49.         }  
  50.         else if ("GetHashCode".Equals(methodName))  
  51.         {  
  52.             invocation.ReturnValue = GetHashCode();  
  53.         }   
  54.     }  
  55. }  
  56.  

4.實體初始化

在映射文件中定義< tuplizers>映射,NHibernate提供的IInstantiator接口實現(xiàn)負責初始化實體實例,這里就是使用Castle.DynamicProxy.ProxyGenerator的public object CreateInterfaceProxyWithoutTarget(System.Type interfaceToProxy, System.Type[] additionalInterfacesToProxy, params Castle.Core.Interceptor.IInterceptor[] interceptors )方法創(chuàng)建一個接口代理。

  1. /// < summary> 
  2. /// 利用NH2.1新特性Tuplizers提供的IInstantiator接口實現(xiàn)負責初始化實體/組件實例  
  3. /// < /summary> 
  4. public class EntityInstantiator : IInstantiator  
  5. {  
  6.     private static readonly ProxyGenerator proxyGenerator = new ProxyGenerator();  
  7.     private readonly Type t;  
  8.  
  9.     public EntityInstantiator(Type entityType)  
  10.     {  
  11.         t = entityType;  
  12.     }  
  13.  
  14.     public object Instantiate()  
  15.     {  
  16.         return Instantiate(null);  
  17.     }  
  18.  
  19.     public object Instantiate(object id)  
  20.     {  
  21.         return  
  22.             proxyGenerator.CreateInterfaceProxyWithoutTarget(t, new[] { typeof(IProxyMarker), t }, new DataProxyHandler(t.FullName, id));  
  23.     }  
  24.     /// < summary> 
  25.     /// 判斷是否實例化  
  26.     /// < /summary> 
  27.     /// < param name="obj">< /param> 
  28.     /// < returns>< /returns> 
  29.     public bool IsInstance(object obj)  
  30.     {  
  31.         try  
  32.         {  
  33.             return t.IsInstanceOfType(obj);  
  34.         }  
  35.         catch (Exception e)  
  36.         {  
  37.             throw new Exception("could not get handle to entity-name as interface : " + e);  
  38.         }  
  39.     }  
  40. }  
  41.  

5.重寫PocoEntityTuplizer

這才是我們真正自定義的Tuplizer,在映射中使用,重寫NHibernate提供的POCO的PocoEntityTuplizer的初始化方法,返回上面實體初始化類完成的創(chuàng)建一個接口代理。

  1. /// < summary>  
  2. /// 重寫PocoEntityTuplizer  
  3. /// < /summary>  
  4. public class EntityTuplizer : PocoEntityTuplizer  
  5. {  
  6.     public EntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) : base(entityMetamodel, mappedEntity) { }  
  7.  
  8.     protected override IInstantiator BuildInstantiator(PersistentClass persistentClass)  
  9.     {  
  10.         return new EntityInstantiator(persistentClass.MappedClass);  
  11.     }  
  12. }  
  13.  

6.實體攔截

NHibernate可以利用NHibernate.IInterceptor實現(xiàn)攔截這個實體:可以去攔截我們創(chuàng)建一個System.Type代理將出現(xiàn)無法預測的值,在這里我僅僅返回上面定義的IProxyMarker標記數(shù)據(jù)的實體名稱,對于其他類型的實體則返回空值。

  1. /// < summary>  
  2. /// 利用NHibernate.IInterceptor對這個實體實現(xiàn)攔截  
  3. /// < /summary>  
  4. public class EntityNameInterceptor : EmptyInterceptor  
  5. {  
  6.     public override string GetEntityName(object entity)  
  7.     {  
  8.         return ExtractEntityName(entity) ?? base.GetEntityName(entity);  
  9.     }  
  10.  
  11.     private static string ExtractEntityName(object entity)  
  12.     {  
  13.         // Our custom Proxy instances actually bundle their appropriate entity name,   
  14.         //so we simply extract it from there if this represents one of our proxies; otherwise, we return null   
  15.         var pm = entity as IProxyMarker;  
  16.         if (pm != null)  
  17.         {  
  18.             var myHandler = pm.DataHandler;  
  19.             return myHandler.EntityName;  
  20.         }  
  21.         return null;  
  22.     }   
  23. }  
  24.  

7.EntityFactory

我們創(chuàng)建一個實體工廠,所謂工廠就是New出來實體的一個制造工廠。我們可以var user = entityFactory.NewEntity< IUser>()這樣初始化一個實體。

  1. public class EntityFactory  
  2. {  
  3.     private static readonly ProxyGenerator proxyGenerator = new ProxyGenerator();  
  4.  
  5.     public T NewEntity< T>()  
  6.     {  
  7.         Type t = typeof(T);  
  8.         return 
  9.             (T)  
  10.             proxyGenerator.CreateInterfaceProxyWithoutTarget(t, new[] { typeof(IProxyMarker), t },  
  11.                                                              new DataProxyHandler(t.FullName, 0));  
  12.     }  
  13. }  
  14.  

上面那些部分相當于一個前奏,為使用tuplizer做準備,我們可以在映射中使用我們自定義的Tuplizer了。

8.映射

這時需要映射這個接口了,使用< tuplizer>映射,這個映射有兩個屬性,分別為class和entity-mode。在這個例子中我在IUser中按照POCO實體模型自定義EntityTuplizer實現(xiàn)來映射。

  1. < class name="IUser"> 
  2.     < tuplizer class="EntityTuplizer" entity-mode="poco"/> 
  3.     < id name="Id"> 
  4.         < generator class="hilo"/> 
  5.     < /id> 
  6.     < property name="Name"/> 
  7. < /class> 

9.測試

測試一下我們的結果吧。分別創(chuàng)建、查詢、刪除操作吧。

[Test]

  1. public void UserCrud()  
  2. {  
  3.     object savedId;  
  4.     var user = entityFactory.NewEntity< IUser>();  
  5.     user.Name = "李永京";  
  6.  
  7.     using (var session = sessions.OpenSession())  
  8.     using (var tx = session.BeginTransaction())  
  9.     {  
  10.         savedId = session.Save(user);  
  11.         tx.Commit();  
  12.     }  
  13.  
  14.     using (var session = sessions.OpenSession())  
  15.     using (var tx = session.BeginTransaction())  
  16.     {  
  17.         user = session.Get< IUser>(savedId);  
  18.         Assert.That(user, Is.Not.Null);  
  19.         Assert.That(user.Name, Is.EqualTo("李永京"));  
  20.         session.Delete(user);  
  21.         tx.Commit();  
  22.     }  
  23.  
  24.     using (var session = sessions.OpenSession())  
  25.     using (var tx = session.BeginTransaction())  
  26.     {  
  27.         user = session.Get< IUser>(savedId);  
  28.         Assert.That(user, Is.Null);  
  29.         tx.Commit();  
  30.     }  
  31. }  
  32.    

結語

由于NHibernate資料很少,所以我從源碼中找到這個例子稍微說明下,大家對Tuplizer有什么好的想法可以回復討論下咯,我想這個功能的擴展就是如果NHibernate Domain與WPF結合,我需要在所有Domain中實現(xiàn)INotifyPropertyChanged接口,就需要重新實現(xiàn)DataProxyHandler。

【編輯推薦】

  1. 使用LINQ查詢泛型字典Dictionary
  2. 淺析Linq to SQL更新數(shù)據(jù)時容易忽略的問題
  3. 淺談LINQ to SQL集成數(shù)據(jù)庫語言優(yōu)劣
  4. LINQ橫向對比foreach方法
  5. 淺談LINQ如何插入刪除和更新數(shù)據(jù)庫記錄備注
責任編輯:yangsai 來源: 博客園
相關推薦

2013-05-20 10:25:45

vSphere 5.1vMotion

2018-09-19 16:15:18

MySQL直方圖數(shù)據(jù)庫

2017-01-09 16:25:55

Android Shortcuts系統(tǒng)

2011-03-24 09:22:36

Java 7JDBC4

2011-05-20 09:43:23

JDK7

2024-04-24 10:31:20

PostgreSQL數(shù)據(jù)庫

2009-07-08 09:47:49

Scala 2.8Scala

2012-07-02 10:43:49

JVMGroovyJava

2011-05-20 09:35:22

JDK7

2010-08-10 09:08:29

HTMLTemplatFlex4

2020-05-14 11:19:19

降序索引子集

2009-05-25 15:42:03

Visual StudC#

2021-11-01 19:49:55

React組件模式

2023-05-31 15:45:49

HCS鴻蒙

2009-07-20 16:44:56

ASP.NET MVCIValueProvi

2010-07-19 11:01:55

SQL Server

2011-05-20 10:28:29

JDK7

2011-05-20 09:53:00

JDK7

2011-05-20 10:15:06

JDK7

2009-06-03 16:10:34

OpenSolaris
點贊
收藏

51CTO技術棧公眾號