Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp
Hi,
I have a problem with a bidirectional many-to-one relationship between address and contact entities as mapped below. Basically a contact
is mapped one-to-one with address. The contact table DDL looks like this:
# Host: localhost
# Database: lettings
# Table: 'contact'
#
CREATE TABLE `contact` (
`id` int(11) NOT NULL auto_increment,
`title_id_fk` int(11) NOT NULL default '0',
`first_name` varchar(50) NOT NULL default '',
`second_name` varchar(50) NOT NULL default '',
`middle_name_1` varchar(50) default NULL,
`middle_name_2` varchar(50) default NULL,
PRIMARY KEY (`id`),
KEY `title_ind` (`title_id_fk`),
CONSTRAINT `contact_ibfk_1` FOREIGN KEY (`title_id_fk`) REFERENCES `type` (`id`)
) TYPE=InnoDB;
Notice that the contact table has NO address foreign key.
The address table is mapped many-to-one with contact. The address table looks like this:
# Host: localhost
# Database: lettings
# Table: 'address'
#
CREATE TABLE `address` (
`id` int(11) NOT NULL auto_increment,
`line_1` varchar(100) NOT NULL default '',
`line_2` varchar(100) default NULL,
`line_3` varchar(100) default NULL,
`line_4` varchar(100) default NULL,
`line_5` varchar(100) default NULL,
`city` varchar(50) NOT NULL default '',
`postcode` varchar(10) NOT NULL default '',
`area_id_fk` int(11) NOT NULL default '0',
`contact_id_fk` int(11) NOT NULL default '0',
PRIMARY KEY (`id`),
UNIQUE KEY `contact_id_fk` (`contact_id_fk`),
KEY `area_ind` (`area_id_fk`),
KEY `contact_ind` (`contact_id_fk`),
CONSTRAINT `address_ibfk_1` FOREIGN KEY (`area_id_fk`) REFERENCES `area` (`id`),
CONSTRAINT `address_ibfk_2` FOREIGN KEY (`contact_id_fk`) REFERENCES `contact` (`id`)
) TYPE=InnoDB;
Notice that there IS a contact foreign key in the address table.
Now my problem is this. I currently create a Contact instance in memory and I then create the address instance in memory and set it as the Contact instances' address.
If I try and save the employer then I get an SQL exception complaining that the insert into address table cannot have a null contact_id_fk.
That is, there is nothing to tell hibernate that because an address has been set for a particular contact, that address's contact should be set to the contact (ie. make the association bidirectional).
Is there anyway to give hibernate a hint about this? Currently, just before my save of the Contact, I make this call:
contact.getAddress().setContact(contact);
which does the job.
But it seems a little unecessary.
Is there a way to make relationships bidirectional in hibernate, even though this bidirectionality is not strictly supported by the schema?
thanks a lot for any help - all the mappings etc. are below.
Neil
Hibernate version:2.1.7c
Mapping documents:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="org.thorne.lettings.util.Type" table="type">
<id name="id" column="id" unsaved-value="-1">
<generator class="identity"/>
</id>
<discriminator column="type" type="string"/>
<property name="description" column="description"/>
<subclass name="org.thorne.lettings.referencedata.api.MaritalStatusImpl" discriminator-value="maritalStatus"/>
<subclass name="org.thorne.lettings.referencedata.api.EmploymentTypeImpl" discriminator-value="employment"/>
<subclass name="org.thorne.lettings.referencedata.api.TitleImpl" discriminator-value="title"/>
</class>
<class name="org.thorne.lettings.referencedata.api.AreaImpl" table="area">
<id name="id" column="id" unsaved-value="-1">
<generator class="identity"/>
</id>
<property name="name" column="name"/>
<property name="population" column="population"/>
<set name="addresses" cascade="all" inverse="true" >
<key column="area_id_fk"/>
<one-to-many class="org.thorne.lettings.referencedata.api.AddressImpl"/>
</set>
</class>
<class name="org.thorne.lettings.referencedata.api.TelephoneNumberImpl" table="telephone_number">
<id name="id" column="id" unsaved-value="-1">
<generator class="identity"/>
</id>
<property name="areaCode" column="area_code"/>
<property name="number" column="number"/>
<many-to-one name="contact" class="org.thorne.lettings.referencedata.api.Contact" column="contact_id_fk" cascade="all" />
</class>
<class name="org.thorne.lettings.referencedata.api.AddressImpl" table="address">
<id name="id" column="id" unsaved-value="-1">
<generator class="identity"/>
</id>
<property name="line1" column="line_1"/>
<property name="line2" column="line_2"/>
<property name="line3" column="line_3"/>
<property name="line4" column="line_4"/>
<property name="line5" column="line_5"/>
<property name="city" column="city"/>
<property name="postCode" column="postcode"/>
<many-to-one name="contact" class="org.thorne.lettings.referencedata.api.Contact" column="contact_id_fk" cascade="none"/>
<many-to-one name="area" class="org.thorne.lettings.referencedata.api.AreaImpl" column="area_id_fk" cascade="none" />
</class>
<class name="org.thorne.lettings.referencedata.api.Contact" table="contact">
<id name="id" column="id" unsaved-value="-1">
<generator class="identity"/>
</id>
<component name="personName" class="org.thorne.lettings.referencedata.api.PersonNameImpl">
<property name="firstName" column="first_name"/>
<property name="secondName" column="second_name"/>
<property name="middleName1" column="middle_name_1"/>
<property name="middleName2" column="middle_name_2"/>
<many-to-one name="title" class="org.thorne.lettings.referencedata.api.TitleImpl" column="title_id_fk" cascade="none" />
</component>
<one-to-one name="address" class="org.thorne.lettings.referencedata.api.AddressImpl" property-ref="contact" cascade="all"/>
<one-to-one name="homeNumber" class="org.thorne.lettings.referencedata.api.TelephoneNumberImpl" cascade="all" />
<one-to-one name="workNumber" class="org.thorne.lettings.referencedata.api.TelephoneNumberImpl" cascade="all"/>
<one-to-one name="mobileNumber" class="org.thorne.lettings.referencedata.api.TelephoneNumberImpl" cascade="all"/>
<joined-subclass name="org.thorne.lettings.referencedata.api.TenantImpl" table="tenant">
<key column="id"/>
<many-to-one name="maritalStatus" class="org.thorne.lettings.referencedata.api.MaritalStatusImpl" column="marital_status_id_fk" cascade="none" />
<property name="pets" column="has_pets"/>
<property name="petDescription" column="pet_description"/>
<property name="smoker" column="is_smoker"/>
<property name="children" column="has_children"/>
<component name="employmentDetails" class="org.thorne.lettings.referencedata.api.EmploymentDetailsImpl" >
<many-to-one name="employmentType" class="org.thorne.lettings.referencedata.api.EmploymentTypeImpl" column="employment_type_id_fk" cascade="none" />
<property name="occupation"/>
<many-to-one name="employer" class="org.thorne.lettings.referencedata.api.EmployerImpl" column="employer_id_fk" cascade="none" />
</component>
</joined-subclass>
<joined-subclass name="org.thorne.lettings.referencedata.api.EmployerImpl" table="employer">
<key column="id"/>
<set name="employees" cascade="none" inverse="true" >
<key column="employer_id_fk"/>
<one-to-many class="org.thorne.lettings.referencedata.api.TenantImpl"/>
</set>
</joined-subclass>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close(): Managed by Spring Framework
Full stack trace of any exception that occurs:
Name and version of the database you are using:MySQL 4.0.18
The generated SQL (show_sql=true):
Debug level Hibernate log excerpt: