#nhibernate #nhibernate-mapping
#nhibernate #nhibernate-сопоставление
Вопрос:
Я довольно новичок в NHibernate, и мне нужно задать пару вопросов, относящихся к очень частому сценарию. Следующий упрощенный пример иллюстрирует проблему.
У меня есть две таблицы с именами Equipment и Users. Пользователи — это набор системных администраторов. Оборудование — это набор механизмов.
Таблицы:
- Таблица Users содержит идентификатор пользователя int и имя входа nvarchar(64).
- Таблица оборудования имеет EquipId int, EquipType nvarchar(64), обновленный с помощью int.
Поведение:
- Системные администраторы могут вносить изменения в оборудование, и когда они это делают, в поле UpdatedBy оборудования «обычно» устанавливается их идентификатор пользователя.
- Пользователи могут быть удалены в любое время.
- Новые элементы оборудования имеют значение UpdatedBy, равное null.
На оборудовании нет ограничений по внешнему ключу.Обновлено, что означает:
- Оборудование.UpdatedBy может иметь значение null.
- Оборудование.Значение UpdatedBy может быть = существующий пользователь.Значение идентификатора пользователя
- Оборудование.Значение UpdatedBy может быть = несуществующий пользователь.Значение идентификатора пользователя
Чтобы найти оборудование и кто последним обновлял оборудование, я мог бы запросить следующим образом:
выберите 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");
}
}
При оборудовании.UpdatedBy = 3 и пользователей нет.userId = 3, вышеуказанный сбой
У меня также есть ощущение, что сгенерированный SQL — это select all from Equipment, за которым следует множество столбцов select от Users, где userId = n, тогда как я ожидал, что NHibernate присоединится влево в соответствии с моим обычным SQL и выполнит одно нажатие. Если я могу указать NHibernate выполнить запрос одним нажатием, как мне это сделать?
В моем проекте важно время, поэтому я с благодарностью принимаю любую помощь, которую вы могли бы предоставить. Если вы размышляете о том, как NHibernate может работать в этом сценарии, пожалуйста, скажите, что вы не совсем уверены. Большое спасибо.
Ответ №1:
В вашем отображении добавьте not-null= false, например:
<many-to-one name="UpdatedBy" class="User" column="UpdatedBy" not-null="false" />
В вашем коде не проверяйте, установлена ли у пользователя страна, чтобы узнать, была ли она кем-либо обновлена. Если пользователь имеет значение null, это вызовет исключение NullPointerException. Вместо этого проверьте, имеет ли пользователь значение null:
User user = item.UpdatedBy;
if (user != null)
Debug.WriteLine("Updated By: " user.LoginName);
else
Debug.WriteLine("Updated by: Nobody");
Комментарии:
1. Спасибо. Возможно ли заставить NHibernate получать все данные за один заход?
2. Вы могли бы просто настроить критерии для получения всех пользователей, подключенных к оборудованию. Или получите все оборудование, к которому подключен пользователь, и выполните итерацию по оборудованию так же, как и раньше.
3. Есть ли у вас какие-либо приблизительные примеры такого запроса criteria api. Я нахожу Criteria api самой сложной частью hibernate для понимания. Я постоянно просматриваю свои существующие sql-запросы и думаю, как, черт возьми, выразить все это с помощью Criterions api.