При использовании cascade = "all-delete-orphan" NHibernate удаляет дочернюю строку, которая не является осиротевшей - она просто перемещается в нового родителя.
using (var session = sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
// Get the store we're moving him to
Store newStore = session.QueryOver<Store>().Where(...).SingleOrDefault();
// Get existing employee
Employee jack = session.QueryOver<Employee>().Where(...).SingleOrDefault();
// Do the move
jack.Store.Staff.Remove(jack);
jack.Store = newStore;
jack.Store.Staff.Add(jack);
transaction.Commit();
}
}
Когда происходит фиксация, aгенерируется один оператор DELETE для удаления «jack» из базы данных.Такое поведение имело бы смысл, если бы «jack» фактически был осиротевшим, но теперь он должен быть счастливо назначен в его новое хранилище.
Если я изменю каскад на «all», генерируется ожидаемый оператор UPDATEи «Джек» счастливо переназначен, как и ожидалось.Однако это приводит к тому, что подлинные потерянные строки остаются в базе данных, что недопустимо.
Это ошибка или что-то не так?
Вотклассы:
public class Store
{
public virtual Guid Id { get; private set; }
public virtual string Name { get; set; }
public virtual IList<Employee> Staff { get; set; }
}
public class Employee
{
public virtual Guid Id { get; private set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual Store Store { get; set; }
}
и отображения FluentNHibernate:
public class EmployeeMap : ClassMap<Employee>
{
public EmployeeMap()
{
Id(x => x.Id).GeneratedBy.Guid();
Map(x => x.FirstName);
Map(x => x.LastName);
References(x => x.Store);
}
}
public class StoreMap : ClassMap<Store>
{
public StoreMap()
{
Id(x => x.Id).GeneratedBy.Guid();
Map(x => x.Name);
HasMany(x => x.Staff)
.Inverse()
.Cascade.AllDeleteOrphan();
}
}
ОБНОВЛЕНИЕ
После еще нескольких испытаний это кажетсяошибка в том, что порядок загрузки объектов изменяет результаты (обратите внимание, что перемещение сотрудника выполняется в обоих случаях, как указано выше):
1) Загрузка хранилища B, загрузка хранилища A, поиск сотрудника в A.Staff, Переместить сотрудника в B ==> Сотрудник удален (исключение не выдано, Сотрудник не вставлен заново)
2) Загрузить хранилище A, Загрузить хранилище B, Найти сотрудника в A.Staff, Переместить сотрудника в B ==> ObjectDeletedException (удаленный объект будет повторно сохранен каскадно (удалить удаленный объект из ассоциаций))
Второй случай - это сценарий, на который ссылается@Cole W и обсуждали здесь и ееe и известное ограничение обработки сирот в NHibernate.
Тем не менее, первый случай представляется ошибкой.В моем понимании не должно быть сценария, в котором порядок загрузки объектов изменяет изменения базы данных, сделанные NHibernate.Кажется, это ошибка, которая потенциально может привести к потере данных.
ОБНОВЛЕНИЕ 2
Учитывая несогласованное поведение, которое зависит от порядка загрузки и потенциальной потери данных, которые у меня естьзарегистрировал это как ошибку в NHibernate JIRA .Отчет об ошибке содержит полный код и сопоставления для демонстрации проблемы.