Учебники

NHibernate — Каскады

В этой главе мы расскажем, как использовать функцию Cascade. Если у вас есть набор или коллекция предметов или отношения между двумя классами, такими как наш клиент и заказ, и у вас есть связь с внешним ключом. Если мы удаляем клиента по умолчанию, NHibernate ничего не делает с дочерними объектами, поэтому те, которые принадлежат этому клиенту, и мы могли бы быть заказами-сиротами.

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

  • По умолчанию NHibernate не связывает операции с дочерними объектами.

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

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

  • Таким образом, вся идея каскадов состоит в том, чтобы рассказать NHibernate, как обращаться с дочерними объектами.

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

По умолчанию NHibernate не связывает операции с дочерними объектами.

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

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

Таким образом, вся идея каскадов состоит в том, чтобы рассказать NHibernate, как обращаться с дочерними объектами.

Существуют разные варианты каскадирования, а именно:

  • none — это значение по умолчанию и это означает отсутствие каскадирования.

  • все, что собирается каскадом, сохраняет, обновляет и удаляет.

  • save-update — это будет каскад, сохранения и обновления.

  • удалить — это будет каскадное удаление.

  • all-delete-orphan — это специальный файл, который довольно часто используется и такой же, как All Except, если он находит строки Delete-orphan, он также удаляет их.

none — это значение по умолчанию и это означает отсутствие каскадирования.

все, что собирается каскадом, сохраняет, обновляет и удаляет.

save-update — это будет каскад, сохранения и обновления.

удалить — это будет каскадное удаление.

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 , он будет сохранять, обновлять и удалять.

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

Это в конечном итоге делает удаление. При этом будет указано удаление из таблицы заказов, где идентификатор клиента равен клиенту, которого вы удаляете.

Таким образом, вы можете каскадировать эти удаления. Так что с 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>

Поэтому, если мы создаем новый заказ, к нему присоединяется новый клиент и мы говорим: сохраните этот заказ, возможно, мы захотим это сделать каскадно. Но одна вещь, которую мы, вероятно, не хотели бы делать, — это удаление заказа для удаления соответствующего клиента.

Итак, здесь мы хотели бы сделать обновление для сохранения, поэтому с помощью сохранения-обновления оно будет каскадно сохранять или сохранять любые обновления для этого клиента. Так что, если мы получим нового клиента или поменяем клиента, это будет каскадным. Если это удаление, оно не удалит это из базы данных.

Итак, запустив наше приложение снова, все по-прежнему работает, как и ожидалось.

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...

Теперь вы должны взглянуть на свое приложение, помните, что по умолчанию установлено значение «Нет», и вам нужно подумать о ваших сущностях и ваших отношениях между ними, чтобы определить соответствующие каскады для каждой из ваших сущностей, а также для каждого из ваших отношений в этой базе данных.