I'm currently working on a small PoC project and decided to take NHibernate for a spin for the persistence part.
I have defined the following domain entities:
- Location: abstract class representing a location (root of the location tree)
- FixedLocation: abstract class representing a geographically fixed location (derives from Location)
- Country: represents a country (derives from Location)
- City: represents a city within a country (derives from Location and cannot logically exist without a Country)
Requirements:
- All locations must ultimately derive from Location (relationally, all Location descendants will share the same range of database keys)
- A bidirectional relationship should exist between Country and City
- Deletes should cascade throughout the entity tree, e.g. deleting a Country should also delete the associated Cities
Here's how I mapped the above classes
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="AET.PoC.Domain" namespace="AET.PoC.Domain.Entities">
<class name="Location" table="Locations" abstract="true">
<id name="Id" type="Int64" unsaved-value="0">
<generator class="native" />
</id>
<property name="LocationType" access="readonly" />
</class>
<joined-subclass name="FixedLocation" table="FixedLocations" extends="Location" abstract="true">
<key column="LocationId" />
<component name="GPSPosition" class="GPSPosition">
<property name="Latitude" type="double" />
<property name="Longitude" type="double" />
</component>
</joined-subclass>
<joined-subclass name="Country" table="Countries" extends="FixedLocation">
<key column="FixedLocation开发者_高级运维Id" />
<property name="Name" length="50" not-null="true" />
<set name="CitySet" cascade="all, delete-orphan" inverse="true">
<key column="CountryId" foreign-key="FK_City_Country" on-delete="cascade" />
<one-to-many class="City" />
</set>
</joined-subclass>
<joined-subclass name="City" table="Cities" extends="FixedLocation">
<key column="FixedLocationId" />
<many-to-one name="Country" class="Country" column="CountryId" not-null="true" cascade="all, delete-orphan" />
<property name="Name" length="50" not-null="true" />
</joined-subclass>
</hibernate-mapping>
Mapping these classes this way fullfils the above requirements, or at least partially...
When I Delete() a Country entity (say location ID 1) that has 2 associated City objects (say location IDs 2 and 3), this is what happens:
- The record with FixedLocationId=1 is deleted from the Countries table
- The records with FixedLocationId=2 and 3 are deleted from the Cities table
- The record with LocationId=1 is deleted from the FixedLocations table
- The record with Id=1 is deleted from the Locations table
So far, so good, but...
- The records with LocationId=2 and 3 are not deleted from the FixedLocations table
- The records with Id=2 and 3 are not deleted from the Locations table
What am I doing wrong here? Can this be done in the first place?
I tried setting the on-delete="cascade" attribute in the of the tags but that made NHibernate complain about circular cascading not being allowed...
Do not put cascades on many-to-one in City. Instead make sure that every location knows about child locations:
<class name="Location" table="Locations" abstract="true">
....
<many-to-one name="_parent" column="ParentLocationID" />
....
<set name="_childLocations" table="Locations" inverse="true" cascade="all-delete-orphan" >
<key column="ParentLocationID" />
<one-to-many class="Location"/>
</set>
....
</class>
This way you have your hierarchy and objects life cycle working and cascaded properly. You can take of other requirements in subclasses.
精彩评论