Руководство по применению каскада NHibernate Definitive
Существуют ли какие-либо интернет-ресурсы, которые имеют исчерпывающее руководство ко всем параметрам каскада для NHibernate, которые будут включать примеры структуры классов, HBM и последствия действий с каждой из настроек каскада для всех отношений с NH.
Также было бы полезно, если бы были примеры для общих ассоциаций, которые можно было бы сделать наиболее правильным образом, например, настроить таблицу состояний, в которой вы никогда не закончите каскад, удалив состояние или удалив объект, у которого есть созданныйBy Пользовательское свойство никогда не удалит пользователя в каскаде и т.д.
Ответы
Ответ 1
Ниже приведена ссылка на Java Hibernate http://docs.jboss.org/hibernate/stable/core/manual/en-US/html/objectstate.html#objectstate-transitive для NHiberate 3.0 (то есть текущая строка svn).
Для каждой основной операции сеанса NHibernate, включая Persist(), Merge(), SaveOrUpdate(), Delete(), Lock(), Refresh(), Evict(), Replicate() - есть соответствующий каскад стиль. Соответственно, каскадные стили называются persist, merge, save-update, delete, lock, refresh, evict, replicate. Каскадный стиль для Save() и Update() - это save-update; для SaveAndUpdateCopy() это слияние; и для PersistOnFlush() он сохраняется. И удалить это псевдоним для удаления.
Если вы хотите, чтобы операция была каскадирована вдоль ассоциации, вы должны указать это в документе сопоставления. Например:
<one-to-one name="person" cascade="persist"/>
Каскадные стили мои сочетаются:
<one-to-one name="person" cascade="persist,delete,lock"/>
Вы можете использовать cascade = "all", чтобы указать, что все операции должны быть каскадированы вдоль ассоциации. По умолчанию cascade = "none" указывает, что никакие операции не должны каскадироваться.
Специальный каскадный стиль, delete-orphan, применяется только к ассоциациям "один ко многим" и указывает, что операция Delete() должна применяться к любому дочернему объекту, который удален из ассоциации. И all-delete-orphan - это то же самое, что и все, delete-orphan.
Рекомендации:
- Как правило, не имеет смысла включать каскад в < много-к-одному > или < много-ко-многим > ассоциация. Каскад часто полезен для < один к одному > и < один-ко-многим > ассоциации.
- Если срок жизни дочернего объекта ограничен продолжительностью жизни родительского объекта, сделайте его объектом жизненного цикла, указав cascade = "all-delete-orphan".
- В противном случае вам может не понадобиться каскад. Но если вы думаете, что часто будете работать с родителем и детьми вместе в одной и той же транзакции, и вы хотите сохранить себе некоторую типизацию, рассмотрите возможность использования cascade = "persist, merge, save-update".
Сопоставление ассоциации (либо однозначной ассоциации, либо коллекции) с cascade = "all" обозначает ассоциацию как отношение родительского/дочернего стиля, где сохранение/обновление/удаление родительского объекта приводит к сохранению/обновлению/удалению ребенка или детей. Ребенок, который не получает ответа от своего родителя, автоматически не удаляется, за исключением случая с < one-to-many > ассоциация, сопоставленная с каскадом = "delete-orphan". Точная семантика каскадных операций для отношения родительский/дочерний выглядит следующим образом:
- Если родительский объект передан в Persist(), все дети передаются в Persist()
- Если родительский объект передан в Merge(), все дочерние элементы передаются в Merge()
- Если родительский элемент передан в Save(), Update() или SaveOrUpdate(), все дочерние элементы передаются в SaveOrUpdate()
- Если переходный или отдельный дочерний объект ссылается постоянным родителем, он передается в SaveOrUpdate()
- Если родитель удален, все дети передаются в Delete()
- Если дочерние элементы разыменовываются постоянным родителем, ничего особенного не происходит - приложение должно явно удалять дочерний элемент, если необходимо, если только cascade = "delete-orphan", и в этом случае ребенок-сироту удаляется.
Ответ 2
Это может быть очевидный совет, но я бы предложил просмотреть старый пост, сделанный Ayende. Быстрый search для NHibernate и каскада на его сайте показал несколько интересных сообщений. Однако они могут быть слишком скудными для ваших нужд.
Даже если это не интернет-ресурс как таковой, я бы также рекомендовал NHibernate в действии. Он подробно рассматривает каскады в главах 3, 4 и 6. Книга нацелена на NHibernate 1.2. Однако я верю, что появится новое издание книги, ориентированное на выпуск NHibernate 3.0; возможно, стоит обратить внимание.
Насколько мне хотелось бы видеть окончательное руководство к каскадам, я его не видел. Возможно, вы могли бы подытожить некоторые из сообщений в блоге, где обсуждаются каскады с вашим собственным сообщением в вашем собственном блоге.
Ответ 3
Я не знаю никакого "окончательного" руководства, но лучший ресурс, который я знаю, - это сообщение в блоге от Айенде, который является одним из окончательных гуру в NHibernate:
NHibernate Cascades: разные между всеми, все-удалить-сироты и сохранить-обновить
Для меня я использую только cascade="none"
и cascade="all"
. all-delete-orphan
иногда является опцией. Все остальное подозрительно. Например, почему я должен неявно создавать экземпляр, потому что он ссылается, когда он живет дольше, чем содержащий объект? Для меня есть только две ситуации: либо объект является зависимым, либо независимым.
Ответ 4
Принятый ответ объясняет это в деталях файлами HBM. Этот ответ охватывает то же самое с Mapping By Code. Они почти одинаковы; только что сопоставлены с их строками HBM.
Форма статьи Айенде хорошо объясняет это:
-
нет - не делайте никаких каскадов, пусть пользователи сами их обрабатывают.
- save-update - когда объект сохраняется/обновляется, проверяйте ассоциации и сохраняйте/обновляйте любой объект, который требует его (включая сохранение/обновление ассоциаций в сценарии "многие ко многим").
- удалить - при удалении объекта удаляются все объекты в ассоциации.
- delete-orphan - при удалении объекта удаляются все объекты в ассоциации. В дополнение к этому, когда объект удаляется из ассоциации и не связан с другим объектом (осиротевшим), также удаляйте его.
- все - при сохранении/обновлении/удалении объекта проверьте ассоциации и сохраните/обновите/удалите все найденные объекты.
- all-delete-orphan - когда объект сохраняется/обновляется/удаляется, проверяйте ассоциации и сохраняйте/обновляйте/удаляйте все найденные объекты. В дополнение к этому, когда объект удаляется из ассоциации и не связан с другим объектом (осиротевшим), также удаляйте его.
Кроме того, этот вопрос объясняет несколько внутренних реализаций Cascade
.
[Flags]
public enum Cascade
{
None = 0,
Persist = 2,
Refresh = 4,
Merge = 8,
Remove = 16,
Detach = 32,
ReAttach = 64,
DeleteOrphans = 128,
All = 256,
}
private static IEnumerable<string> CascadeDefinitions(this Cascade source)
{
if (source.Has(Cascade.All))
{
yield return "all";
}
if (source.Has(Cascade.Persist))
{
yield return "save-update, persist";
}
if (source.Has(Cascade.Refresh))
{
yield return "refresh";
}
if (source.Has(Cascade.Merge))
{
yield return "merge";
}
if (source.Has(Cascade.Remove))
{
yield return "delete";
}
if (source.Has(Cascade.Detach))
{
yield return "evict";
}
if (source.Has(Cascade.ReAttach))
{
yield return "lock";
}
if (source.Has(Cascade.DeleteOrphans))
{
yield return "delete-orphan";
}
}
Обратите внимание, что Cascade.All
не включает в себя Cascade.DeleteOrphans
. В этом случае вам может понадобиться включить его, используя Cascade.All | Cascade.DeleteOrphans
.
В качестве альтернативы вы можете использовать метод расширения Include
Cascade.All.Include(Cascade.DeleteOrphans)
.
В сочетании с Cascade
вам может потребоваться также изучить Inverse
; это указывает на владельца ассоциации. Для получения дополнительной информации см. этот вопрос и этот ответ.