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.