使用Castle DynamicProxy代理NHibernate对象可以吞噬NH功能

时间:2012-03-27 08:59:06

标签: nhibernate proxy interceptor castle-dynamicproxy

我最近做了一些被认为太可怕的事情,但我个人很喜欢这种实验。这是电报风格描述:

  • 使用NH获取数据对象
  • 每个DataObject都由CastleDynamicProxy
  • 包装
  • 当查询使用自定义属性修饰的属性时,重定向到自己的代码而不是NHibernate以获得Returnvalue。

对象创建/数据获取代码

Objects=GetAll().Select(x=>ProxyFactory.CreateProxy<T>(x)).ToList();

public IList<Person> GetAll()
{
    ISession session = SessionService.GetSession();
    IList<Person> personen = session.CreateCriteria(typeof(Person))
                          .List<Person>();
    return personen;
}

代理生成代码:

public T CreateProxy<T>(T inputObject)
{
    T proxy = (T)_proxyGenerator.CreateClassProxy(typeof(T), new ObjectRelationInterceptor<T>(inputObject));
    return proxy;
}

使用的拦截器定义如下:

    public class MyInterceptor<T> : IInterceptor
    {
        private readonly T _wrappedObject;

        public MyInterceptor(T wrappedObject)
        {
            _wrappedObject = wrappedObject;
        }

        public void Intercept(IInvocation invocation)
        {
            if (ShouldIntercept(invocation)) { /* Fetch Data from other source*/ }
            else
            {
                invocation.ReturnValue = invocation.Method.Invoke(_wrappedObject, invocation.Arguments);
            }
        }


        public bool ShouldIntercept(IInvocation invocation)
        {
            // true if Getter / Setter and Property
            // has a certain custom attribute
        }
    }

这在没有NHibernate的环境中工作正常(在代码中创建对象,其中Object拥有自己的数据)。 不幸的是,else在侦听方法部分似乎离开NHibernate的未官能化,似乎_wrappedObject减小到它的基本类型的功能(而不是由NHibernate的被代理),所以所有映射的子集保持为空

我尝试从lazy切换到eager加载(并确认所有SQL都已执行),但这根本不会改变任何内容。

有人知道我能做些什么才能恢复工作吗?

提前多多感谢!

1 个答案:

答案 0 :(得分:1)

我发现我所做的是部分错误而且部分不完整。我没有删除这个问题,而是选择自己回答,以便其他人也可以从中受益。

首先,我误解了类代理是一个实例代理,这就是我存储_wrappedObject的原因。我需要Object来执行invocation.Method.Invoke(_wrappedObject, invocation.Arguments),这是下一个错误。我应该通过使用invocation.Proceed()将调用传递给下一个拦截器而不是这样做。

现在,不完整的地方在哪里? NH似乎需要知道有关它的实例的元数据,所以我错过了一条重要的路线,让NH知道代理是其亲属之一:

SessionFactory.GetClassMetadata(entityName).SetIdentifier(instance, id, entityMode);

这只适用于NHibernate拦截器,因此最终产品与我最初的产品略有不同......足够的胡言乱语,你可以在Ayende的website上看到一个非常易于理解的例子。他的精彩教程的大道具!