Как оптимизация в NHibernate запросе и лучшая производительность

#c# #performance #nhibernate #nhibernate-mapping #lazy-loading

#c# #Производительность #nhibernate #nhibernate-отображение #отложенная загрузка

Вопрос:

У меня есть проект с помощью реализации NHibernate и с использованием отложенной загрузки. В этом проекте у меня есть два класса: Person и PersonIdentity. Связь между этими двумя — агрегация, означает, что у человека есть один PersonIdentity.

Сопоставление пользователей — это :

 <class name="Person" table="Person_Person" >

    <id name="Id" type="Int64" unsaved-value="0">
      <generator class="native" />
    </id>

    <version name="Version" />

    <property name="Name" column="Name"
              type="String(255)"  access="property" not-null="false" />

    <one-to-one name="Identity" property-ref="Person"
      class="Domain.Entities.PersonIdentity,Domain.Entities" cascade="delete" fetch="select" />

</class>
  

Сопоставление PersonIdentity является :

     <id name="Id" type="Int64" unsaved-value="0" >
      <generator class="native" />
    </id>

    <property name="FirstName" column="FirstName" type="String(255)"  access="property" not-null="false" />

    <property name="LastName" column="LastName" type="String(255)"  access="property" not-null="false" />

    <many-to-one name="Person" column="Person_id_fk" uniqe="true" class="Domain.Entities.Person,Domain.Entities"
      outer-join="auto" fetch="select" access="property" not-null="true" />

  </class>
  

Моя проблема в производительности. Когда я выполняю запрос только для человека, подобного этому :

 var q = SessionInstance.Query<Person>();
IList list = q.ToList<Person>();
  

Я ожидаю только выполнения

 SELECT * FROM Person_Person
  

Но, кроме того, для каждого пользователя в базе данных выполните запрос, подобный этому :

 SELECT * FROM Person_Identiyt WHERE Id = 1;
SELECT * FROM Person_Identiyt WHERE Id = 2;
SELECT * FROM Person_Identiyt WHERE Id = 3;
...
  

И, согласно ленивому подходу, это нехорошо,
PersonIdentity не должен загружаться до его вызова.
Как я могу загружать только пользователей без PersonIdentity для первой загрузки?

Комментарии:

1. Для человека всегда есть идентификатор

Ответ №1:

Прокси (отложенная загрузка) никогда не используются для необязательных взаимно-однозначных запросов.

Прокси всегда означает, что что-то есть, но в случае взаимно однозначного возможно, что в другой таблице не существует строки. И поскольку прокси-сервер не может удалить себя из свойства owner (и установить для него значение null), прокси-серверы не могут использоваться.

Если ваша база данных гарантирует, что всегда существует идентификатор (внешний ключ от пользователя к идентификатору), вы можете добавить constrained="true" к взаимно однозначному, и NHibernate будет использовать прокси.

Обходные пути:

  • Всегда загружайте идентификатор (с fetch="join" ), чтобы избежать проблемы выбора n 1. (Примечание: Если я правильно помню, может быть ошибка, которая в этом случае все еще выполняет n 1. Смотрите NHibernate Jira.)
  • Сопоставьте ссылку как коллекцию и предоставьте свойство в вашем классе Person, которое вызывает collection.SingleOrDefault() . Таким образом, вы можете использовать отложенную загрузку.

Комментарии:

1. Я добавил constrained="true" отношение «один к одному» для PersonIdentity в Person hbm. Но существуют две проблемы: при вставке и удалении Person возникает ошибка с таким сообщением: свойство not-null ссылается на домен с нулевым или временным значением. Сущности. PersonIdentity. Человек. Но обновление верно. Почему?

2. Почему из-за этого изменения, Домен. Сущности. PersonIdentity. Person является временным? Но перед добавлением constrained="true" это было правильно? также, когда GetByID(x) для Person еще в каждом случае дополнительно Select * from Person_Person выполняется второй запрос для Select * from Person_identity where ID = x . Почему?

3. @ehsanzeynali Пожалуйста, опубликуйте сопоставление PersonIdentity и код, который вы используете для сохранения и загрузки объектов.

4. Я добавил сопоставление PersonIdentity к вопросу. Мой код : Person person = new Person(); person.PersonIdentity.FirstName = "Jack"; SessionInstance.Save(person);

5. @ehsanzeynali Ошибка, подождите. Взаимно однозначное отношение к свойству (а не к первичному ключу) constrained="true" не имеет смысла. Как NHibernate должен это вставить? Identity требуется уже вставленный Person , и вы сказали NHibernate, что он должен быть вставлен Identity первым (с constrained="true" помощью). Это решение не будет работать для вас. Некоторые другие несвязанные моменты: (1) type="String(255)" тоже не имеет смысла. Я полагаю, вы имеете в виду sql-type="String(255)" . (2) Вы должны добавить unique="true" на стороне «многие к одному» вашего «один к одному», иначе это не настоящее «один к одному».