您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“NHibernate2.1新特性之Tuplizers怎么用”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“NHibernate2.1新特性之Tuplizers怎么用”這篇文章吧。
Tuplizers?這個(gè)單詞在英文字典里沒有解釋,和元組(tuple)這個(gè)單詞有點(diǎn)相似,在NHibernate中應(yīng)該翻譯為元組片斷,Tuplizers只在映射中提供,所以叫元組片段映射比較合適。
我們平時(shí)一般使用Domain Entity,然后使用< class>來映射,對(duì)Domain Entity操作。在NHibernate中,對(duì)于Domain Entity的Entity Mode為POCO類型,這時(shí)對(duì)應(yīng)的tuplizer知道通過其構(gòu)造方法來創(chuàng)建一個(gè)POCO,再通過其屬性訪問器來訪問POCO屬性。
Tuplizers,其完整命名空間是NHibernate.Tuple.Tuplizer,它就是根據(jù)給定的NHibernate.EntityMode,來復(fù)現(xiàn)片斷數(shù)據(jù)。如果給定的片斷數(shù)據(jù)被認(rèn)為其是一種數(shù)據(jù)結(jié)構(gòu),"tuplizer"就是一個(gè)知道如何創(chuàng)建這樣的數(shù)據(jù)結(jié)構(gòu),以及如何給這個(gè)數(shù)據(jù)結(jié)構(gòu)賦值的東西。
在NHibernate中有NHibernate.Tuple.Entity.IEntityTuplizer和NHibernate.Tuple.Component.IComponentTuplizer兩個(gè)接口,IEntityTuplizer負(fù)責(zé)管理上面提到的實(shí)體的契約,而IComponentTuplizer則是針對(duì)組件的。
下面從NHibernate源碼中摘取一個(gè)典型的例子來說明Tuplizer的用法。
典型實(shí)例
我想映射一個(gè)接口,對(duì)這個(gè)接口按照POCO實(shí)體模型進(jìn)行持久化操作。首先想到應(yīng)該可以New出來這個(gè)接口,使用工廠可以產(chǎn)生出來。在初始化這個(gè)接口的時(shí)候要重寫一些NHibernate默認(rèn)的POCO行為,在對(duì)這個(gè)接口賦值的時(shí)候攔截一些操作,記錄下這個(gè)接口。獲取接口時(shí)候同樣也需要攔截。
1.Domain
public interface IUser { int Id { get; set; } string Name { get; set; } }
我們需要映射這個(gè)接口,但是NHibernate只會(huì)去映射類,我們?cè)趺慈ジ膶懘a讓NHibernate可以像類那樣去映射接口呢?這就是Tuplizers的功能。
2.代理標(biāo)記proxy marker
由于這里是特殊需要,我對(duì)其這個(gè)代理做個(gè)標(biāo)記,如果某個(gè)實(shí)體可以轉(zhuǎn)換為這個(gè)代理標(biāo)記接口就說明是我重寫定義的Domain,
/// < summary> /// 代理標(biāo)記 /// 對(duì)象實(shí)例是代理的一個(gè)實(shí)例 /// < /summary> public interface IProxyMarker { DataProxyHandler DataHandler { get; } }
3.DataProxy
利用Castle的攔截器IInterceptor接口對(duì)這個(gè)代理數(shù)據(jù)進(jìn)行攔截,例如在獲取這個(gè)代理數(shù)據(jù)的時(shí)候,讓NHibernate按照POCO那樣去把其數(shù)據(jù)保存到一個(gè)字典中。
/// < summary> /// 利用Castle的攔截器,代理數(shù)據(jù)DataProxy /// < /summary> public sealed class DataProxyHandler:IInterceptor { private readonly Dictionary< string, object> data = new Dictionary< string, object>(50); private readonly string entityName; public DataProxyHandler(string entityName, object id) { this.entityName = entityName; data["Id"] = id; } public string EntityName { get { return entityName; } } public IDictionary< string, object> Data { get { return data; } } public void Intercept(IInvocation invocation) { invocation.ReturnValue = null; string methodName = invocation.Method.Name; if ("get_DataHandler".Equals(methodName)) { invocation.ReturnValue = this; } else if (methodName.StartsWith("set_")) { string propertyName = methodName.Substring(4); data[propertyName] = invocation.Arguments[0]; } else if (methodName.StartsWith("get_")) { string propertyName = methodName.Substring(4); object value; data.TryGetValue(propertyName, out value); invocation.ReturnValue = value; } else if ("ToString".Equals(methodName)) { invocation.ReturnValue = EntityName + "#" + data["Id"]; } else if ("GetHashCode".Equals(methodName)) { invocation.ReturnValue = GetHashCode(); } } }
4.實(shí)體初始化
在映射文件中定義< tuplizers>映射,NHibernate提供的IInstantiator接口實(shí)現(xiàn)負(fù)責(zé)初始化實(shí)體實(shí)例,這里就是使用Castle.DynamicProxy.ProxyGenerator的public object CreateInterfaceProxyWithoutTarget(System.Type interfaceToProxy, System.Type[] additionalInterfacesToProxy, params Castle.Core.Interceptor.IInterceptor[] interceptors )方法創(chuàng)建一個(gè)接口代理。
/// < summary> /// 利用NH2.1新特性Tuplizers提供的IInstantiator接口實(shí)現(xiàn)負(fù)責(zé)初始化實(shí)體/組件實(shí)例 /// < /summary> public class EntityInstantiator : IInstantiator { private static readonly ProxyGenerator proxyGenerator = new ProxyGenerator(); private readonly Type t; public EntityInstantiator(Type entityType) { t = entityType; } public object Instantiate() { return Instantiate(null); } public object Instantiate(object id) { return proxyGenerator.CreateInterfaceProxyWithoutTarget(t, new[] { typeof(IProxyMarker), t }, new DataProxyHandler(t.FullName, id)); } /// < summary> /// 判斷是否實(shí)例化 /// < /summary> /// < param name="obj">< /param> /// < returns>< /returns> public bool IsInstance(object obj) { try { return t.IsInstanceOfType(obj); } catch (Exception e) { throw new Exception("could not get handle to entity-name as interface : " + e); } } }
5.重寫PocoEntityTuplizer
這才是我們真正自定義的Tuplizer,在映射中使用,重寫NHibernate提供的POCO的PocoEntityTuplizer的初始化方法,返回上面實(shí)體初始化類完成的創(chuàng)建一個(gè)接口代理。
/// < summary> /// 重寫PocoEntityTuplizer /// < /summary> public class EntityTuplizer : PocoEntityTuplizer { public EntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) : base(entityMetamodel, mappedEntity) { } protected override IInstantiator BuildInstantiator(PersistentClass persistentClass) { return new EntityInstantiator(persistentClass.MappedClass); } }
6.實(shí)體攔截
NHibernate可以利用NHibernate.IInterceptor實(shí)現(xiàn)攔截這個(gè)實(shí)體:可以去攔截我們創(chuàng)建一個(gè)System.Type代理將出現(xiàn)無法預(yù)測(cè)的值,在這里我僅僅返回上面定義的IProxyMarker標(biāo)記數(shù)據(jù)的實(shí)體名稱,對(duì)于其他類型的實(shí)體則返回空值。
/// < summary> /// 利用NHibernate.IInterceptor對(duì)這個(gè)實(shí)體實(shí)現(xiàn)攔截 /// < /summary> public class EntityNameInterceptor : EmptyInterceptor { public override string GetEntityName(object entity) { return ExtractEntityName(entity) ?? base.GetEntityName(entity); } private static string ExtractEntityName(object entity) { // Our custom Proxy instances actually bundle their appropriate entity name, //so we simply extract it from there if this represents one of our proxies; otherwise, we return null var pm = entity as IProxyMarker; if (pm != null) { var myHandler = pm.DataHandler; return myHandler.EntityName; } return null; } }
7.EntityFactory
我們創(chuàng)建一個(gè)實(shí)體工廠,所謂工廠就是New出來實(shí)體的一個(gè)制造工廠。我們可以var user = entityFactory.NewEntity< IUser>()這樣初始化一個(gè)實(shí)體。
public class EntityFactory { private static readonly ProxyGenerator proxyGenerator = new ProxyGenerator(); public T NewEntity< T>() { Type t = typeof(T); return (T) proxyGenerator.CreateInterfaceProxyWithoutTarget(t, new[] { typeof(IProxyMarker), t }, new DataProxyHandler(t.FullName, 0)); } }
上面那些部分相當(dāng)于一個(gè)前奏,為使用tuplizer做準(zhǔn)備,我們可以在映射中使用我們自定義的Tuplizer了。
8.映射
這時(shí)需要映射這個(gè)接口了,使用< tuplizer>映射,這個(gè)映射有兩個(gè)屬性,分別為class和entity-mode。在這個(gè)例子中我在IUser中按照POCO實(shí)體模型自定義EntityTuplizer實(shí)現(xiàn)來映射。
< class name="IUser"> < tuplizer class="EntityTuplizer" entity-mode="poco"/> < id name="Id"> < generator class="hilo"/> < /id> < property name="Name"/> < /class>
9.測(cè)試
測(cè)試一下我們的結(jié)果吧。分別創(chuàng)建、查詢、刪除操作吧。
[Test]
public void UserCrud() { object savedId; var user = entityFactory.NewEntity< IUser>(); user.Name = "李永京"; using (var session = sessions.OpenSession()) using (var tx = session.BeginTransaction()) { savedId = session.Save(user); tx.Commit(); } using (var session = sessions.OpenSession()) using (var tx = session.BeginTransaction()) { user = session.Get< IUser>(savedId); Assert.That(user, Is.Not.Null); Assert.That(user.Name, Is.EqualTo("李永京")); session.Delete(user); tx.Commit(); } using (var session = sessions.OpenSession()) using (var tx = session.BeginTransaction()) { user = session.Get< IUser>(savedId); Assert.That(user, Is.Null); tx.Commit(); } }
結(jié)語
由于NHibernate資料很少,所以我從源碼中找到這個(gè)例子稍微說明下,大家對(duì)Tuplizer有什么好的想法可以回復(fù)討論下咯,我想這個(gè)功能的擴(kuò)展就是如果NHibernate Domain與WPF結(jié)合,我需要在所有Domain中實(shí)現(xiàn)INotifyPropertyChanged接口,就需要重新實(shí)現(xiàn)DataProxyHandler。
以上是“NHibernate2.1新特性之Tuplizers怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。