温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

NHibernate2.1新特性之Tuplizers怎么用

发布时间:2021-12-03 10:37:26 来源:亿速云 阅读:131 作者:小新 栏目:编程语言

这篇文章主要为大家展示了“NHibernate2.1新特性之Tuplizers怎么用”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“NHibernate2.1新特性之Tuplizers怎么用”这篇文章吧。

Tuplizers?这个单词在英文字典里没有解释,和元组(tuple)这个单词有点相似,在NHibernate中应该翻译为元组片断,Tuplizers只在映射中提供,所以叫元组片段映射比较合适。

我们平时一般使用Domain Entity,然后使用< class>来映射,对Domain Entity操作。在NHibernate中,对于Domain Entity的Entity Mode为POCO类型,这时对应的tuplizer知道通过其构造方法来创建一个POCO,再通过其属性访问器来访问POCO属性。

Tuplizers,其完整命名空间是NHibernate.Tuple.Tuplizer,它就是根据给定的NHibernate.EntityMode,来复现片断数据。如果给定的片断数据被认为其是一种数据结构,"tuplizer"就是一个知道如何创建这样的数据结构,以及如何给这个数据结构赋值的东西。

在NHibernate中有NHibernate.Tuple.Entity.IEntityTuplizer和NHibernate.Tuple.Component.IComponentTuplizer两个接口,IEntityTuplizer负责管理上面提到的实体的契约,而IComponentTuplizer则是针对组件的。

下面从NHibernate源码中摘取一个典型的例子来说明Tuplizer的用法。

典型实例

我想映射一个接口,对这个接口按照POCO实体模型进行持久化操作。首先想到应该可以New出来这个接口,使用工厂可以产生出来。在初始化这个接口的时候要重写一些NHibernate默认的POCO行为,在对这个接口赋值的时候拦截一些操作,记录下这个接口。获取接口时候同样也需要拦截。

1.Domain

public interface IUser  {      int Id { get; set; }      string Name { get; set; }  }

我们需要映射这个接口,但是NHibernate只会去映射类,我们怎么去改写代码让NHibernate可以像类那样去映射接口呢?这就是Tuplizers的功能。

2.代理标记proxy marker

由于这里是特殊需要,我对其这个代理做个标记,如果某个实体可以转换为这个代理标记接口就说明是我重写定义的Domain,

/// < summary>  /// 代理标记  /// 对象实例是代理的一个实例  /// < /summary>  public interface IProxyMarker  {      DataProxyHandler DataHandler { get; }  }


3.DataProxy

利用Castle的拦截器IInterceptor接口对这个代理数据进行拦截,例如在获取这个代理数据的时候,让NHibernate按照POCO那样去把其数据保存到一个字典中。

/// < summary>  /// 利用Castle的拦截器,代理数据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.实体初始化

在映射文件中定义< tuplizers>映射,NHibernate提供的IInstantiator接口实现负责初始化实体实例,这里就是使用Castle.DynamicProxy.ProxyGenerator的public object CreateInterfaceProxyWithoutTarget(System.Type interfaceToProxy, System.Type[] additionalInterfacesToProxy, params Castle.Core.Interceptor.IInterceptor[] interceptors )方法创建一个接口代理。

/// < summary> /// 利用NH2.1新特性Tuplizers提供的IInstantiator接口实现负责初始化实体/组件实例  /// < /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>     /// 判断是否实例化      /// < /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的初始化方法,返回上面实体初始化类完成的创建一个接口代理。

/// < 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.实体拦截

NHibernate可以利用NHibernate.IInterceptor实现拦截这个实体:可以去拦截我们创建一个System.Type代理将出现无法预测的值,在这里我仅仅返回上面定义的IProxyMarker标记数据的实体名称,对于其他类型的实体则返回空值。

/// < summary>  /// 利用NHibernate.IInterceptor对这个实体实现拦截  /// < /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

我们创建一个实体工厂,所谓工厂就是New出来实体的一个制造工厂。我们可以var user = entityFactory.NewEntity< IUser>()这样初始化一个实体。

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));      }  }

上面那些部分相当于一个前奏,为使用tuplizer做准备,我们可以在映射中使用我们自定义的Tuplizer了。

8.映射

这时需要映射这个接口了,使用< tuplizer>映射,这个映射有两个属性,分别为class和entity-mode。在这个例子中我在IUser中按照POCO实体模型自定义EntityTuplizer实现来映射。

< class name="IUser">     < tuplizer class="EntityTuplizer" entity-mode="poco"/>     < id name="Id">         < generator class="hilo"/>     < /id>     < property name="Name"/> < /class>

9.测试

测试一下我们的结果吧。分别创建、查询、删除操作吧。

[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();      }  }

结语

由于NHibernate资料很少,所以我从源码中找到这个例子稍微说明下,大家对Tuplizer有什么好的想法可以回复讨论下咯,我想这个功能的扩展就是如果NHibernate Domain与WPF结合,我需要在所有Domain中实现INotifyPropertyChanged接口,就需要重新实现DataProxyHandler。

以上是“NHibernate2.1新特性之Tuplizers怎么用”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI