NHibernate - Cascades
在本章中,我们将介绍如何使用 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>
现在,订单完全属于客户。因此,如果客户从数据库中删除,我们的应用程序将删除所有这些订单,包括任何可能已被遗弃的订单。
它最终会执行删除操作。这样,它将从订单表中删除,其中客户 ID 等于您要删除的客户。
因此,您实际上可以级联这些删除。因此,使用 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...
现在您应该看一下您的应用程序,记住默认值为 None ,您必须考虑您的实体及其之间的关系,以确定每个实体的适当级联以及该数据库中的每个关系。