NHibernate - Каскады
В этой главе мы расскажем, как использовать функцию Cascade. Если у вас есть набор или коллекция элементов или отношения между двумя классами, такими как наш клиент и заказ, и есть отношения внешнего ключа. Если мы удалим клиента по умолчанию, NHibernate ничего не сделает с дочерними объектами, поэтому те, которые принадлежат этому клиенту, и мы можем потерять заказы.
Мы также могли нарушить ограничения внешнего ключа, поэтому мы можем использовать понятие каскадов.
По умолчанию NHibernate не выполняет каскадные операции с дочерними объектами.
Причина этого в том, что у вас могут быть отношения, например, у клиента, имеющего адрес доставки по умолчанию, и этот адрес доставки используется множеством разных клиентов.
Таким образом, вы не захотите обязательно каскадировать эти отношения, потому что другие клиенты все еще ссылаются на них.
Таким образом, вся идея каскадов состоит в том, чтобы сообщить NHibernate, как обращаться с дочерними объектами.
Существуют различные варианты каскадирования, а именно:
none - это значение по умолчанию, которое означает отсутствие каскадирования.
all - который будет каскадно сохранять, обновлять и удалять.
save-update - он будет каскадно сохраняться и обновляться.
delete - будет каскадное удаление.
all-delete-orphan - это специальный, который довольно часто используется и аналогичен All Except, если он находит строки Delete-orphan, он их также удаляет.
Вы можете указать значение по умолчанию в своем hbm.xml файл, поэтому вы можете предоставить каскад по умолчанию для этого элемента сопоставления Hibernate, или вы также можете указать его для определенных коллекций и отношений, таких как многие-к-одному.
Давайте посмотрим на простые примеры каскадов, давайте исправим проблему в программе, где нам нужно вручную каскадировать сохранение заказов, как показано в следующем коде.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
foreach (var order in newCustomer.Orders) {
session.Save(order);
}
id = newCustomer.Id;
tx.Commit();
}
В приведенном выше фрагменте кода вы можете видеть, что мы вручную сохраняем все заказы для клиента. Теперь удалим ручной каскадный код, в котором сохраняются все заказы.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
Нам нужно указать опцию каскада в customer.hbm.xml.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Теперь заказы полностью принадлежат покупателю. Таким образом, если клиенты были удалены из базы данных, наше приложение здесь захочет удалить все эти заказы, включая те, которые могли быть потеряны.
В конечном итоге он выполнит удаление. При этом он скажет удалить из таблицы заказов, где идентификатор клиента равен клиенту, которого вы удаляете.
Таким образом, вы действительно можете каскадировать эти удаления. Так что сAll, он будет сохранять, обновлять и удалять.
Теперь, когда вы запустите это приложение, вы увидите следующий результат.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
Press <ENTER> to exit...
Как видите, мы удалили код из программы, которая выполнялась каскадом вручную, и наше приложение все еще работает.
Так что, в зависимости от ваших отношений, вы можете захотеть их каскадировать. Теперь давайте посмотрим на другое каскадное отношение. Давай пойдем вOrder.hbm.xml файл, и мы можем каскадировать отношения "многие к одному".
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Order" table = "`Order`">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "Ordered"/>
<property name = "Shipped"/>
<component name = "ShipTo">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<many-to-one name = "Customer" column = "CustomerId" cascade = "save-update"/>
</class>
</hibernate-mapping>
Итак, если мы создаем новый заказ и к нему прикреплен новый клиент, и мы говорим: сохраните этот заказ, мы можем захотеть его каскадировать. Но одна вещь, которую мы, вероятно, не захотим делать, - это если будет удален заказ для удаления соответствующего клиента.
Итак, здесь мы хотели бы выполнить обновление сохранения, поэтому, используя save-update, он будет каскадировать любые сохранения или обновления для этого клиента. Итак, если мы получим нового клиента или если мы меняем клиента, это будет каскадно. Если это удаление, оно не удалит его из базы данных.
Итак, запустив наше приложение снова, все по-прежнему работает, как ожидалось.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
Press <ENTER> to exit...
Теперь вы должны взглянуть на свое приложение, помните, что значение по умолчанию - Нет, и вам нужно подумать о своих сущностях и своих отношениях между ними, чтобы определить соответствующие каскады для каждой из ваших сущностей, а также для каждой из ваших отношений в этой базе данных.