Отображение и запрос NHibernate в тех случаях, когда таблицы связаны, но нет ограничений по внешнему ключу - PullRequest
1 голос
/ 16 апреля 2010

Я довольно новичок в NHibernate, и мне нужно задать пару вопросов, касающихся очень частого сценария. Следующий упрощенный пример иллюстрирует проблему.

У меня есть две таблицы с именами Оборудование и Пользователи. Пользователи - это набор системных администраторов. Оборудование представляет собой набор машин.

Таблица:

  • Таблица пользователей имеет UserId int и LoginName nvarchar (64).
  • Таблица оборудования имеет EquipId int, EquipType nvarchar (64), ОбновленоBy int.

Поведение:

  • Системные администраторы могут вносить изменения в оборудование, и когда они это делают, поле «Обновленное оборудование» «обычно» устанавливается на свой идентификатор пользователя.
  • Пользователи могут быть удалены в любое время.
  • Новые предметы экипировки имеют значение Updates, равное нулю.

На Equipment.UpdatedBy нет ограничений по внешнему ключу, что означает:

  • Equipment.UpdatedBy может быть нулевым.
  • Значение Equipment.UpdatedBy может быть = существующее значение User.UserId
  • Значение Equipment.UpdatedBy может быть = несуществующее значение User.UserId

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

выберите E.EquipId, E.EquipName, U.UserId, U.LoginName из оборудования E левое внешнее объединение Пользователи U вкл. E.UpdatedBy = U.UserId

Достаточно просто.

Так как это сделать в NHibernate?

Мои отображения могут быть следующими:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
  namespace="Data"
  assembly="Data">

  <class name="User" table="Users">
    <id name="Id" column="UserId" unsaved-value="0">
      <generator class="native" />
    </id>
    <property name="LoginName" unique="true" not-null="true" />
  </class>

  <class name="Equipment" table="Equipment">
    <id name="Id" column="EquipId" type="int" unsaved-value="0">
      <generator class="native" />
    </id>
    <property name="EquipType" />
    <many-to-one name="UpdatedBy" class="User" column="UpdatedBy" />
  </class>

</hibernate-mapping>

Так как мне получить все предметы экипировки и кто их обновил?

   using (ISession session = sessionManager.OpenSession())
   {
      List<Data.Equipment> equipList =
         session
            .CreateCriteria<Data.Equipment>()
            // Do I need to SetFetchmode or specify that I
            // want to join onto User here? If so how?
            .List<Data.Equipment>();

      foreach (Data.Equipment item in equipList)
      {
         Debug.WriteLine("\nEquip Id: " + item.Id);
         Debug.WriteLine("Equip Type: " + item.EquipType);

         if (item.UpdatedBy != null)
            Debug.WriteLine("Updated By: " + item.UpdatedBy.LoginName);
         else
            Debug.WriteLine("Updated by: Nobody");
      }
   }

Когда Equipment.UpdatedBy = 3, а Users.UserId = 3 отсутствует, вышеприведенный сбой

У меня также есть ощущение, что сгенерированный SQL - это выбор всего из Оборудования , за которым следуют многие выбор столбцов в Users, где UserId = n , тогда как я ожидал, что NHibernate оставит соединение согласно моему простому обычному SQL и сделать один удар. Если я скажу NHibernate сделать запрос одним нажатием, как мне это сделать?

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

1 Ответ

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

В вашем отображении добавьте not-null = false, например:

<many-to-one name="UpdatedBy" class="User" column="UpdatedBy" not-null="false" />

В своем коде не проверяйте, настроена ли для пользователя страна, чтобы узнать, обновлялся ли он кем-либо. Если пользователь имеет значение null, это приведет к исключению NullPointerException. Вместо этого проверьте, является ли Пользователь нулевым:

User user = item.UpdatedBy;
if (user  != null)
    Debug.WriteLine("Updated By: " + user.LoginName);
else
    Debug.WriteLine("Updated by: Nobody");
...