NHibernate - kaskady
W tym rozdziale omówimy, jak korzystać z funkcji Cascade. Jeśli masz zestaw lub kolekcję elementów lub relację między dwiema klasami, takimi jak nasz klient i zamówienie, i masz relację z kluczem obcym. Jeśli domyślnie usuniemy klienta, NHibernate nie zrobi nic z obiektami podrzędnymi, więc te, które należą do tego klienta, a my możemy być osieroconymi zamówieniami.
Moglibyśmy również naruszać ograniczenia klucza obcego, więc możemy użyć pojęcia kaskad.
Domyślnie NHibernate nie wykonuje kaskadowych operacji na obiektach podrzędnych.
Powodem tego jest to, że możesz mieć relacje, takie jak klient mający domyślny adres wysyłki, a adres wysyłki jest udostępniany wielu różnym klientom.
Więc nie chcesz kaskadować tej relacji koniecznie, ponieważ inni klienci wciąż się do niej odnoszą.
Zatem cała koncepcja kaskad polega na tym, aby powiedzieć NHibernate, jak ma postępować z jednostkami podrzędnymi.
Istnieją różne opcje kaskadowania, które są następujące -
none - co jest domyślne i oznacza brak kaskadowania.
all - który będzie kaskadowo zapisywał, aktualizował i usuwał.
save-update - będzie kaskadować, zapisywać i aktualizować.
delete - będzie usuwać kaskadowo.
all-delete-orphan - jest to specjalny, który jest dość często używany i jest taki sam jak All Except, jeśli znajdzie wiersze Delete-orphan, usunie również te wiersze.
Możesz określić wartość domyślną w pliku hbm.xml plik, dzięki czemu można podać domyślną kaskadę dla tego elementu mapowania Hibernate lub można ją również określić dla określonych kolekcji i relacji, takich jak wiele do jednego.
Rzućmy okiem na proste przykładowe kaskady, naprawmy problem w programie, w którym musimy ręcznie kaskadować zapisywanie do zamówień, jak pokazano w poniższym kodzie.
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();
}
W powyższym fragmencie kodu widać, że ręcznie zapisujemy wszystkie zamówienia dla klienta. Teraz usuńmy ręczny kod kaskadowy, w którym zapisane są wszystkie zamówienia.
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();
}
Musimy określić opcję kaskady w 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>
Teraz zamówienia w całości należą do klienta. Więc jeśli klienci zostaliby usunięci z bazy danych, nasza aplikacja chciałaby usunąć wszystkie te zamówienia, w tym te, które mogły zostać osierocone.
Skończy się na usuwaniu. W ten sposób powie usuń z tabeli zamówień, gdzie identyfikator klienta jest klientem, którego usuwasz.
Możesz więc faktycznie kaskadować te usunięcia. Tak więc zAll, będzie zapisywać, aktualizować i usuwać.
Teraz po uruchomieniu tej aplikacji zobaczysz następujące dane wyjściowe.
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...
Jak widać, usunęliśmy kod z programu, który ręcznie kaskadował, a nasza aplikacja nadal działa.
Więc w zależności od twojego związku, możesz chcieć je kaskadować. Przyjrzyjmy się teraz innej relacji kaskadowej. Chodźmy doOrder.hbm.xml file i możemy kaskadować tę relację wiele do jednego.
<?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>
Więc jeśli utworzymy nowe zamówienie i jest do niego dołączony nowy klient, i powiemy, że zapiszemy to zamówienie, możemy chcieć to kaskadowo. Ale jedna rzecz, której prawdopodobnie nie chcielibyśmy robić, to usuwanie zamówienia w celu usunięcia odpowiedniego klienta.
Więc tutaj chcielibyśmy zrobić aktualizację zapisu, więc używając save-update, będzie ona kaskadowo zapisywać wszystkie zapisy lub aktualizacje tego klienta. Tak więc, jeśli zdobędziemy nowego klienta lub jeśli zmienimy klienta, będzie to kaskadowo. Jeśli jest to usunięcie, nie usunie tego z bazy danych.
Po ponownym uruchomieniu naszej aplikacji wszystko nadal działa zgodnie z oczekiwaniami.
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...
Teraz powinieneś spojrzeć na swoją aplikację, pamiętaj, że domyślną wartością jest Brak i musisz pomyśleć o swoich encjach i relacjach między nimi, aby określić odpowiednie kaskady dla każdego z twoich encji, a także dla każdej relacji w tej bazie danych.