Предупреждение о сужении прокси NHibernate - PullRequest
7 голосов
/ 25 ноября 2011

Мы создаем приложение ASP.NET MVC, использующее NH для доступа к данным. Используя NH Profiler, я вижу много предупреждений, таких как «WARN: Сужение прокси до Domain.CaseTask - эта операция прерывается ==». Я получаю их очень часто при выполнении запросов для классов, которые отображаются в таблице для каждого подкласса, например, с использованием поставщика NH Linq:

Query<ICaseTask>().Where(c => c.Assignee == Of || c.Operator == Of)

, где класс CaseTask наследует от Task, вызывает предупреждение.

Информация о предупреждении в Интернете скудна и в основном намекает на то, что это что-то, что следует игнорировать ... О чем конкретно предупреждает это предупреждение? Должно ли это быть что-то, что я должен попытаться исправить?

Ответы [ 2 ]

5 голосов
/ 25 июля 2017

Реальность сложнее.Когда вы загружаете сущность с помощью session.Load или обращаетесь к свойству с отложенной загрузкой, NHibernate возвращает прокси-объект.Этот прокси-объект будет гидратирован (данные будут загружены из БД) при первом обращении к любому из его свойств.Для этого NHibernate генерирует прокси-класс, который расширяет класс сущностей и переопределяет все методы получения и установки свойств.Это прекрасно работает, когда наследование не используется, поскольку у вас не будет возможности провести различие между прокси и классом сущности (базовый класс прокси), например, простой тест proxy is MyEntity всегда будет работать.

Теперь представьте, что у нас есть Personentity:

class Person {
  // lazy-loaded
  public Animal Pet { get; set; }
}

И у нас также есть Animal иерархия классов:

public abstract class Animal { ... }
public class Cat { ... }
public class Dog { ... }

Теперь предположим, что свойство Pet загружено с отложенной загрузкой, когда вы спрашиваете NHibernate о человеке, у вас будетполучить объект прокси:

var pet = somePerson.Pet; // pet will be a proxy

Но так как Pet является лениво загруженным свойством, NH не будет знать, будет ли он экземпляром Cat или Dog, поэтому он будет делать все возможное исоздаст прокси, который расширяет Animal.Прокси-сервер пройдет тестирование для pet is Animal, но не пройдет тесты для pet is Cat или pet is Dog.

Теперь предположим, что вы получите доступ к некоторому свойству объекта pet, заставив NH загрузить данные из БД.Теперь NH будет знать, что ваш питомец, например, Cat, но прокси уже создан и не может быть изменен.Это заставит NHibernate выдать предупреждение о том, что исходный прокси для pet, который расширяет тип Animal, будет сужен до типа Cat.Это означает, что с этого момента прокси-объект для животных с pet.Id, который вы создаете с помощью session.Load<Animal>(pet.Id), будет расширяться Cat с этого момента.Это также означает, что, поскольку Cat теперь хранится как часть сеанса, если мы загрузим второго человека, который делит cat с первым, NH будет использовать уже доступный экземпляр Cat proxy для заполнения свойства lazy -агрегата.

Одним из последствий будет то, что ссылка на объект pet будет отличаться от ссылки, полученной session.Load<Animal>(pet.Id)object.ReferencesEqual смысле).

// example - say parent and child share *the same* pet
var pet = child.Pet; // NH will return proxy that extends Animal
pet.DoStuff(); // NH loads data from DB

var parent = child.Parent; // lazy-loaded property
var pet2 = parent.Pet; // NH will return proxy that extends Cat

Assert.NotSame(pet, pet2);

Теперь, когда это может причинить вам вред:

  1. Когда вы помещаете свои сущности в Set s или Dictionary в своем коде или еслиВы используете любую другую структуру, для работы которой требуется пара Equals/GetHashCode.Это можно легко исправить, предоставив пользовательскую реализацию Equals/GetHashCode (см .: http://www.onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=1)

  2. Когда вы пытаетесь привести прокси-объект к целевому типу, например (Cat)pet, но опять же есть известные решения (например, Получение прокси правильного типа в NHibernate )

Таким образом, мораль состоит в том, чтобы максимально избежать наследования в вашей доменной модели.

2 голосов
/ 28 февраля 2012

Это предупреждение касается классов, имеющих свойства или поля, которые являются подклассом.IE:

public class Animal
{
    public int Id {get;set;}
}

public class Cat : Animal
{
    public int Weight {get;set;}
}

public class Person
{
    public Cat Pet {get;set;}
}

NHibernate расстраивается, когда загружает сущность человека, потому что он не хочет разыгрывать вас, потому что поведение становится непредсказуемым.Если вы не скажете NHibernate, как обращаться с Equals (среди прочих логики), он не будет знать, как выполнить это сравнение самостоятельно.

Основная идея, чтобы исправить это, состоит в том, чтобы позволить NHibernate поместить объект базового класса вграфик, а затем вы имеете дело с приведением (обратите внимание, что в этой настройке будут использоваться несколько отличающиеся отображения - я сделал это для упрощения кода, но, очевидно, это можно сделать, сохранив свойства как полные методы получения / установки):

public class Animal
    {
        public int Id {get;set;}
    }

public class Cat : Animal
{
    public int Weight {get;set;}
}

public class Person
{
    private Animal _pet;
    public Cat Pet {
        get{return _pet as Cat;}
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...