2013-09-12 2 views
3

Недавно мы обновили до последней версии NHibernate (3.3.3.4001), и у меня возникла проблема, которой не было в NHibernate 2.1.2.4000. Это заставляет меня думать, что это может быть проблемой с новым встроенным провайдером байт-кода.Nhibernate: свойство readonly вызывает большую нагрузку

Рассмотрим следующие отображения:

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Foo.Core.Domain" assembly="Foo.Core" default-access="property"> 
    <class name="EntityA" table="EntityA" lazy="true"> 

    <id name="Id" column="EntityAId"> 
     <generator class="native" /> 
    </id> 

    <many-to-one name="EntityB" column="EntityBId" class="EntityB" not-null="true" /> 
    <many-to-one name="EntityC" column="EntityCId" class="EntityC" not-null="true" access="readonly" insert="true" update="false" /> 


    </class> 
</hibernate-mapping> 


<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Foo.Core.Domain" assembly="Foo.Core" default-access="property"> 
    <class name="EntityB" table="EntityB" lazy="true"> 

    <id name="Id" column="EntityBId"> 
     <generator class="native" /> 
    </id> 

    <many-to-one name="EntityC" column="EntityCId" class="EntityC" not-null="true" /> 

    </class> 
</hibernate-mapping> 

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Foo.Core.Domain" assembly="Foo.Core" default-access="property"> 
    <class name="EntityC" table="EntityC" lazy="true"> 

    <id name="Id" column="EntityCId"> 
     <generator class="native" /> 
    </id> 


    </class> 
</hibernate-mapping> 

Вот мое определение класса EntityA:

Public Class EntityA 

    Public Overridable Property Id As Integer 

    Public Overridable Property EntityB As EntityB 

    Public Overridable ReadOnly Property EntityC As EntityC 
     Get 
      Return If(EntityB IsNot Nothing, EntityB.EntityC, Nothing) 
     End Get 
    End Property 


End Class 

Проблема возникает, когда я называю Session.Get для экземпляра EntityA - это сразу вызывает выберите, который будет выпущен для соответствующего объекта EntityB:

Session.Get(Of EntityA)(id) ' Causes the EntityB that EntityA references to be loaded as well. 

M y лучше всего предположить, что поставщик байт-кода вызывает мое свойство readtoly «EntityC», которое будет оцениваться при создании прокси-сервера, что заставляет нагрузку связанного EntityB.

Есть ли какой-либо способ избежать чрезмерной нагрузки с использованием этого типа модели с NHibernate 3.3.3?

+0

Извините, если глупый комментарий, но, в соответствии с кодом свойства EntityA.EntityC, я не вижу точки EntityA.EntityC, находящейся в сопоставлении (не знал, что вы можете определить явное свойство readonly в VB.Net в то время как AFAIK, вы не можете на C#) – jbl

+0

Чтобы быть ясным, в моей реальной реализации есть смысл в этом (это просто надуманный пример, чтобы проиллюстрировать проблему). Мне нужен столбец для денормализации (см. составление отчетов). – DanP

+0

Насколько я понимаю, для простоты вы создали этот ясный пример. Я был просто озадачен этими двумя определениями, с другой семантикой, EntityA.EntityC, один в сопоставлении и один в коде, и задавался вопросом о ожидаемом поведении прокси-класса. Может быть, вы можете пролить свет на это, поскольку это, кажется, ядро ​​вашей проблемы. – jbl

ответ

1

Я сделал несколько тестов с этой иерархией классов и отображением на NH 3.3.3 SP1, и это мои наблюдения:

  • нагрузка EntityA с помощью session.Get<>, а затем сделать что-то с объектом , не касаясь свойствами EntityB, EntityC, EntityB не будут загружены . Прикосновение к одному из свойств вызовет запрос для , и это нормально.

  • нагрузки EntityA, обновив что-то не связано со свойствами EntityB и EntityC как изменение имени EntityA, то откатить сделки, никаких дополнительных не ВЫБРАТЬ выдается.

  • Загрузить EntityA, ничего не предпринимать, а затем совершить транзакцию, был выдан второй SELECT для EntityB.

  • Загрузить EntityA, выполнить некоторые запросы с сеансом, затем выдается указанный SELECT для EntityB.

Все тесты проводятся под управлением FlushMode.Auto.

Исходя из этого, я пришел к выводу, что поведение NHibernate в этой ситуации вполне ожидаемо: при выполнении флеша NH необходимо проверить на загрязнение объекта, ему нужно получить значение свойства EntityC для сравнения с предыдущим значение, и это то, что вызвало запрос SELECT.

Это определенно не из-за session.Get<> или нового прокси. Вы можете легко сделать больше тестов, чтобы доказать это. Я не понимаю, почему NH 2.1.2 может быть любым другим.

Я также пробовал тесты на NH 3.3.1, ответ был точно таким же, как и в NH 3.3.3 SP1.

+0

Благодарим вас за ввод. Мой тестовый пример попадает в «Load EntityA, ничего не делайте, а затем фиксируйте транзакцию ...», о котором вы говорили выше. Теперь ваш вывод имеет смысл - поэтому давайте рассмотрим мое обновленное сопоставление выше, где у меня есть отношение EntityA -> EntityC, сопоставленное с: insert = "true" update = "false" - не исключено ли это из-за грязной проверки на флеш? – DanP

+0

Просто протестирован. NH Profiler показывает, что второй SELECT все еще выпущен. Похоже, вам понадобится разная компоновка в классах и свойствах или переопределите грязную проверку NHibernate, чтобы избежать этого SELECT. –

Смежные вопросы