识别NHibernate代理类

时间:2010-04-18 22:28:05

标签: c# .net nhibernate

我不是NHibernate用户;我写了一个序列化实用程序库。用户已记录一个功能请求,我应该处理NHibernate代理类,将它们视为与实际类型相同。目前,我的代码将它们视为意外继承,并抛出异常。

代码不会事先知道NHibernate(包括没有参考,但我不是反思;-p)

是否有一种强大/可靠的方法来检测此类代理类型?显然DataContractSerializer处理这个问题,所以我希望它非常简单。也许是一些界面或[attribute]装饰。

此外,在反序列化期间;目前我将创建原始类型(不是NHibernate类型)。这是否适用于持久性目的?或者是否需要代理类型?如果是后者;创建代理类型的实例需要什么?

7 个答案:

答案 0 :(得分:49)

您可以通过将类转换为(不出所料)INHibernateProxy来检测某个类是否为NHibernate代理。

如果您需要获取基础“真实”对象,请使用:

Session.GetSessionImplementation().PersistenceContext.Unproxy(proxiedObject)

您无需测试代理即可调用Unproxy;如果它不是代理,它返回原始参数。

编辑:我现在使用不同的方法来获取底层对象,主要是为了解决延迟加载和继承问题:http://sessionfactory.blogspot.com/2010/08/hacking-lazy-loaded-inheritance.html

答案 1 :(得分:16)

我猜你真的不想访问实际的Nhibernate会话。此代码可能更符合您的需求:

/// <summary>
/// Returns the real type of the given proxy. If the object is not a proxy, it's normal type is returned.
/// </summary>
internal static Type GetRealType(this object proxy)
{
    if (proxy is INHibernateProxy)
    {
        var lazyInitialiser = ((INHibernateProxy)proxy).HibernateLazyInitializer;
        return lazyInitialiser.PersistentClass;
    }
    else
    {
        return proxy.GetType();
    }
}

希望有所帮助。

答案 2 :(得分:8)

NHibernate中有一个工具,您可以在其中提供类型(代理与否),并返回实际类型。 (我正在使用NHibernate 3)

这是您使用它的方式:

var realType = NHibernate.NHibernateUtil.GetClass(proxyInstance);

希望这会有所帮助:D

答案 3 :(得分:1)

NHibernate在运行时创建(代理)原始实体的子类,以便能够进行延迟加载。它只能执行此操作,因为您必须将所有属性标记为“虚拟”。我想不出你如何能够检测到一个对象是一个代理而不是任何其他类型的子类 - 当然不是通用的方式。我只能假设您的代码在这种情况下抛出异常,因为正在(反)序列化的实际类没有标记为可序列化。我认为你唯一可以做的就是放松你的验证或允许子类的序列化,如果它覆盖了它的基类的所有属性。

反序列化为原始类型即可。

答案 4 :(得分:1)

NHibernate 2.1+允许通过配置设置动态代理提供程序。我所知道的实现是Castle(默认),LinFu和Spring。 NHibernate不需要接口或属性。我认为这使得可靠地检测对象是否是代理是不可能的。

当s1mm0t回答时,在反序列化时创建实际类型很好。

答案 5 :(得分:1)

如果您正在编写通用序列化实用程序库,我认为您根本不应该处理该特定情况。您的代码不应该依赖于NHibernate。你应该做的是提供客户端代码可以用来影响你的库操作的钩子。

答案 6 :(得分:1)

Diego的方法在尝试确定对象之前完全加载对象 - 这绝对是最通用的方法,但如果代理已知具体类型,则可能不需要加载对象。

Vijay的方法在预先知道具体类型的情况下更快 - 但正如Diego所指出的那样,在某些情况下,该信息不可用,因为尚未加载确定确切类型所需的信息。

考虑到这两种情况,我想出了以下内容:

https://gist.github.com/1089489

有趣的是:

        if (entity is INHibernateProxy)
        {
            var lazyInitialiser = ((INHibernateProxy)entity).HibernateLazyInitializer;
            var type = lazyInitialiser.PersistentClass;

            if (type.IsAbstract || type.GetNestedTypes().Length > 0)
                return Service.Session.GetSessionImplementation().PersistenceContext.Unproxy(entity).GetType();
            else // we don't need to "unbox" the Proxy-object to get the type
                return lazyInitialiser.PersistentClass;
        }

        return entity.GetType();

首先检查代理背后的类型是否是抽象的,并使用Vijay或Diego的方法,具体取决于具体类型是否已知。

换句话说,如果Proxy后面的类型不是具体类型,或者可能是子类型,它只加载对象。

我做了一个快速的单元测试,以证明这是有效的,但我不认为我已经测试了所有可能的情况 - 我相信这个想法是合理的,但我想听听Diego和Vijay或其他人的评论

谢谢!

编辑:发布了上述要点的更新,使用了另一种可用于Unproxy()实体的通用方法 - 在某些情况下您可能需要这样做...