What I am doing that I am worried is the wrong thing to do is read an object from the database clear out any lists on that object and then re-populate them - potentially with the same data.
I am using NHibernate 1.2.0 in the persistence layer of a multi tier system. The data from the database is being passed upto a front end via a web service.
The top level object I have is
Contact which has a number of one to many relationships hanging of it, such as
ContactAddress and
ContactLanguage. The mapping for Contact looks something like this:
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Services.BusinessEntities.Contact,Services.BusinessEntities" table="Contact">
<id name="Id" column="id" type="Int64" unsaved-value="0">
<generator class="identity"/>
</id>
<bag name="ContactAddressList" inverse="true" lazy="true" cascade="all-delete-orphan">
<key column="contactId" />
<one-to-many class="Services.BusinessEntities.ContactAddress,Services.BusinessEntities" />
</bag>
<bag name="ContactLanguageList" inverse="true" lazy="true" cascade="all-delete-orphan">
<key column="contactId" />
<one-to-many class="Services.BusinessEntities.ContactLanguage,Services.BusinessEntities" />
</bag>
<property column="forename" type="String" name="Forename" not-null="true" length="50" />
<property column="surname" type="String" name="Surname" not-null="true" length="50" />
</class>
</hibernate-mapping>
When I receive a contact from the front-end for writing back to the database, I need to translate the "front-end" contact into a "NHibernate" contact. To do this I re-read the contact from the database, I then use the "front-end" contact to set the new values in the "NHibernate" Contact. For the properties such as forename and surname, this is a straight forward task:
Code:
public static Contact Translate(ContactDataType from)
{
Contact to = contactService.GetContact(from.Id);
to.Forename = from.Forename;
to.Surname = from.Surname;
// etc
return to;
}
The lists however is where I am woried that what I am doing is
fundamentally wrong.
Taking the ContactAddressList as an example, the first thing I do is clear out the list on the "NHibernate" contact. I will then loop through the list of addresses on the front-end contact and for each one, attempt to read it from the database. If the address exists, I add it back into the address list on the "NHibernate" contact, if it doesn't I create a new "NHibernate" address and add that into the list. Finally I update any of the properties on the "NHibernate" contact address with what came back from the front-end. Any addresses that were deleted by the front-end, won't be added into the list and since I have cascade set to all-delete-orphan, they will be deleted, the new ones will be added and any others will be updated:
Code:
public static Contact Translate(ContactDataType from)
{
// etc
// Clear out the addresses - any addresses deleted by the front-end
// won't be added back in and will therefore be deleted when the contact
// is saved
to.ContactAddressList.Clear();
// Convert all of our contact addresses into "NHibernate" addresses
foreach (BusinessEntities.ContactAddress contactAddress in TranslateContactAddressList(from.Addresses, to))
{
// Add the updated and new addresses back into the list for saving to the database
to.ContactAddressList.Add(contactAddress);
}
// etc
return to;
}
private static List<BusinessEntities.ContactAddress> TranslateContactAddressList(List<DataTypes.ContactAddress> from,
BusinessEntities.Contact parent)
{
List<BusinessEntities.ContactAddress> to = new List<BusinessEntities.ContactAddress>();
foreach (DataTypes.ContactAddress address in from)
{
// Business logic layer will catch any exceptions and return null if the address
// doesn't exist.
BusinessEntities.ContactAddress addressBE = contactService.GetContactAddress(from.Id);
// If to is null we are adding a new address otherwise we update the existing one
if(to == null)
{
addressBE = new BusinessEntities.ContactAddress();
}
addressBE.Contact = parent;
addressBE.number = from.number;
addressBE.street = from.street;
// etc
// Add the address back into the list
to.Add(addressBE);
}
return to;
}
I would really appreciate it if someone could confirm one way or another whether what I am doing is OK or not.