Выявление прокси-классов NHibernate - PullRequest
37 голосов
/ 19 апреля 2010

Я не пользователь NHibernate;Я пишу служебную библиотеку сериализации.Пользователь зарегистрировал запрос функции, чтобы я обрабатывал прокси-классы NHibernate, обрабатывая их так же, как и фактический тип.В данный момент мой код обрабатывает их как неожиданное наследование и выдает исключение.

Код не будет знать заранее о NHibernate (включая ссылки, но я не в восторге от размышлений ;-p)

Существует ли надежный / гарантированный способ обнаружения таких типов прокси?Очевидно, DataContractSerializer справляется с этим нормально, так что я надеюсь, что это что-то довольно простое.Возможно какой-то интерфейс или [attribute] украшение.

Также во время десериализации;на данный момент я буду создавать оригинальный тип (не тип NHibernate).Это хорошо для постоянства?Или нужен тип прокси?Если последний;что требуется для создания экземпляра типа прокси?

Ответы [ 7 ]

49 голосов
/ 19 апреля 2010

Вы можете определить, является ли класс прокси-сервером NHibernate, приведя его (неудивительно) к INHibernateProxy.

Если вам нужно получить базовый «реальный» объект, используйте:

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

Вам не нужно проверять прокси для вызова Unproxy; возвращает исходный параметр, если это не прокси.

Редактировать: Теперь я использую другой подход для получения базового объекта, в основном для обхода отложенной загрузки и наследования: http://sessionfactory.blogspot.com/2010/08/hacking-lazy-loaded-inheritance.html

16 голосов
/ 19 апреля 2010

Я предполагаю, что вы на самом деле не хотите получать доступ к реальному сеансу 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();
    }
}

Надеюсь, это поможет.

8 голосов
/ 28 мая 2012

Существует инструмент из NHibernate, в котором вы указываете тип (прокси или нет), и он возвращает реальный тип. (Я использую NHibernate 3)

Вот как вы его используете:

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

Надеюсь, это поможет: D

1 голос
/ 26 июля 2011

Метод Диего полностью загружает объект, прежде чем пытаться определить его тип - это, безусловно, наиболее общий подход, но вам может не потребоваться загрузка объекта, если конкретный тип уже известен Прокси.

Метод Виджая быстрее в тех случаях, когда конкретный тип известен заранее - но, как указал Диего, в некоторых случаях эта информация недоступна, поскольку информация, необходимая для определения точного типа, еще не была загружена.

Принимая во внимание оба сценария, я придумал следующее:

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

Сначала проверяется, является ли тип прокси абстрактным, и использует метод Виджая или Диего, в зависимости от того, известен ли конкретный тип.

Другими словами, он загружает объект только в том случае, если тип за прокси-сервером не является конкретным типом или может иметь подтип.

Я провел быстрый модульный тест, чтобы продемонстрировать, что это работает, но я не думаю, что проверил все возможные случаи - я считаю, что идея правильная, но я хотел бы услышать комментарии Диего и Виджая, или других .

Спасибо!

РЕДАКТИРОВАТЬ: выложил обновление в суть выше, с дополнительным универсальным методом, который может быть использован для Unproxy () сущности - в некоторых случаях вам, возможно, придется сделать это ...

1 голос
/ 21 июня 2010

Если вы пишете универсальную библиотеку утилит сериализации, я не думаю, что вам вообще следует заниматься этим конкретным случаем. Ваш код не должен зависеть от NHibernate. То, что вы должны сделать, это предоставить хуки, которые клиентский код может использовать для воздействия на работу вашей библиотеки.

1 голос
/ 19 апреля 2010

NHibernate 2.1+ позволяет настраивать динамический прокси-сервер через конфигурацию. Реализации, о которых я знаю, это Castle (по умолчанию), LinFu и Spring. NHibernate не требует интерфейса или атрибута. Я думаю, что это делает практически невозможным надежное определение, является ли объект прокси.

Как ответил s1mm0t, создание фактического типа при десериализации - это хорошо.

1 голос
/ 19 апреля 2010

NHibernate создает (прокси) подклассы исходных сущностей во время выполнения, чтобы иметь возможность выполнять отложенную загрузку. Это возможно только потому, что вы вынуждены пометить все свойства как «виртуальные». Я не могу думать о том, как вы могли бы обнаружить, что объект является прокси-сервером, в отличие от любого другого вида подклассов - конечно, не в общем виде. Я могу только предположить, что ваш код вызывает исключение в этом случае, потому что фактический класс, который сериализуется (де), не помечен как сериализуемый. Я думаю, что единственное, что вы можете сделать, это ослабить проверку или разрешить сериализацию подкласса, если он переопределяет все свойства своего базового класса.

Десериализация до исходного типа будет в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...