NHibernate постоянный порядок добавления объекта в коллекцию - PullRequest
3 голосов
/ 25 июля 2011

Я, вероятно, здесь делаю ошибку новичка, но я не могу понять, как сделать эту работу. У меня есть две сущности - Parent и Child, где одна Parent может иметь много Child ren. Кажется, проблема в том, что когда я добавляю нового потомка к родителю, родитель не может каскадно сохранить дочернего, потому что у дочернего экземпляра еще нет идентификатора. С другой стороны, ребенок не может быть сохранен самостоятельно, поэтому у него нет возможности получить удостоверение личности ...

Мои отображения:

public ParentMap()
{ 
    // ID and other properties

    HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad();
}

public ChildMap()
{
    // ID and other properties

    References(c => c.Parent);
}

Теперь, возможно, у меня уже есть родительская запись в моей базе данных, и я хочу добавить дочерний элемент в свою коллекцию дочерних элементов. Для этого я создаю новый экземпляр класса Child, добавляю дочерний элемент к свойству Children родителя (типа IList<Child>). Я также извлекаю родительскую запись и устанавливаю свойство childs Parent для родительского объекта.

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

С Save(p), сохраняя родительскую запись и надеясь, что ребенок будет сохранен на каскаде, я получаю следующую ошибку:

Невозможно вставить значение NULL в столбец 'ChildID', таблица 'dbo.Children'; столбец не допускает нулевые значения. Вставить не удается. Заявление было прекращено.

Если я попробую наоборот, то есть сначала сохраню дочерний элемент, затем добавлю его к родительскому элементу и сохраню родительский, я получу следующую ошибку:

нулевой идентификатор в записи Application.Domain.Entities.Child (не очищать сеанс после возникновения исключения)

В каком порядке я должен позвонить parent.Children.Add(child), child.Parent = parent, session.Save(parent) и session.Save(child), чтобы сделать эту работу? Чего-то не хватает в моей конфигурации сопоставления?

Обновление: Я добавил .Inverse() и безуспешно пробовал следующее:

// First of the above errors
session.Save(child);
child.Parent = parent;
parent.Children.Add(child);
session.Save(parent);

// Second of the above errors
child.Parent = parent;
parent.Children.Add(child);
session.Save(child);
session.Save(parent);

// Second of the above errors
child.Parent = parent;
parent.Children.Add(child);
session.Save(parent);

// Second of the above errors
child.Parent = parent;
parent.Children.Add(child);
session.Save(child);

Ответы [ 3 ]

0 голосов
/ 26 июля 2011

Оказывается, проблема была вовсе не в NHibernate, а скорее в конфигурации моей базы данных - я забыл настроить столбец ID таблицы Children.Как только я указал столбец идентификатора, все заработало как положено: .Inverse() не требуется, и я могу сохранить только Parent, а Child сохраняется в каскаде.

0 голосов
/ 13 мая 2016

мне не хватало Cascade.All() с References.Мы не должны ставить Inverse() на HasMany:

public ParentMap()
{ 
    // ID and other properties

    HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad();
}

public ChildMap()
{
    // ID and other properties

    References(c => c.Parent).Cascade.All();
}
0 голосов
/ 26 июля 2011

Отметьте ваше отношение как Inverse на стороне родителя.Это скажет NHibernate, что сторона ребенка управляет отношением:

HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad().Inverse();

Это вынуждает вас устанавливать child.Parent = parent вручную, но вы все равно делаете это, поэтому я считаю, что это не проблема.

По умолчанию NHibernate предполагает, что ответственность за установку внешнего ключа для ребенка лежит на родителе.И логический порядок операций выглядит примерно так:

  1. Родитель должен быть сохранен
  2. Дочерние объекты сохраняются из-за каскада - у нас пока нет идентификатора родителя (по крайней мере, мы не моглиЯ не знаю, почему это так работает, когда мы тоже это знаем)
  3. Дети вставляются с null во внешний ключ Родителя
  4. После этого родитель успешно вставляется, его идентификатор
  5. У детей есть внешний ключ родителя UPDATEd.

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

Установка Inverse() говорит родителю, что он не заботится о внешнем ключе ребенка, и вы несете ответственность за правильную установку child.Parent.При сохранении в этом случае есть только INSERT, как и ожидалось, и нет попыток установить null во внешнем ключе.

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