NHibernate cascade = "all-delete-orphan" удаляет несиротированные строки - PullRequest
3 голосов
/ 25 октября 2011

При использовании 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 .Отчет об ошибке содержит полный код и сопоставления для демонстрации проблемы.

Ответы [ 2 ]

5 голосов
/ 26 октября 2011

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

Ознакомьтесь с этой статьей SO: Свободное перемещение исключений NHibernate между коллекциями

В этой статье также упоминается эта статьяФабио Мауло:
http://fabiomaulo.blogspot.com/2009/09/nhibernate-tree-re-parenting.html

0 голосов
/ 25 октября 2011

Проблемы, вероятно, вызваны перезаписью нескольких ссылок, не сообщая NHibernate о том, что происходит

Быстрый удар по нему, пока мы ждем обновленного Q (см. Мой комментарий относительно отсутствующего свойства Staff) Iрекомендовал бы изменить ваш запрос так, чтобы вы запрашивали Store напрямую, а не с помощью навигатора Store на объекте Employee.Извлеките гнездо из этой коллекции Store.Staff, введите session.SaveOrUpdate(store), а затем попробуйте перезаписать ссылку jack.Store на новую (введите еще одну SaveOrUpdate до совершения транзакции)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...