While defining our domain model for an application I'm working on at work, we decided to allow for historical versions of entities that are accessible from a collection. In addition, each historical property would have a "current" property that would represent the current valid version of the object. Something like:
Code:
public class Consumer {
//field variables
Demographics currentDemographics;
List allDemographics = new List();
public Demographics getCurrentDemographics() {
return currentDemographics();
}
public void setCurrentDemographics(Demographics d) {
this.currentDemographics.setEffectiveEndDate(new Date());
this.allDemographics.add(d);
this.currentDemographics = d;
}
public List getAllDemographics() {
return this.demographics;
}
}
The Person table here would contain a foreign key reference to the current demographics object for each record.
However, I was concerned about how I could map this, so I tried a simple example at home. Here, I used a Person with multiple addresses, one of which could be a "home" address. The person table has a foreign key column "home_address" referencing this "home address." As I feared, hibernate wasn't too crazy about this concept. The details are below, but basically I get a "duplicate property mapping" exception.
I know that we could rewrite the getter for getCurrentDemographics() to search the collection, but the hope was that we would not have to load the entire collection to retrieve the current information. Can hibernate handle this sort of association, or do I need to search the collection as stated?
I hope this isn't answered somewhere -- I searched everything I could find, but I didn't see this anywhere (although choosing a set of search keywords for this is a bit tough. ;) )
Thanks in advance!
Hibernate version: 3.0.5
Mapping documents:Person.hbm.xml
Code:
<hibernate-mapping package="net.vickerscraven.learning.hibernate">
<class name="Person" table="person">
<id name="id" column="per_id" unsaved-value="null">
<generator class="identity"/>
</id>
<property name="firstName" column="per_first_name" not-null="true"/>
<property name="lastName" column="per_last_name" not-null="true"/>
<property name="birthDate" column="per_birth_date"/>
<property name="weightInKilograms" column="per_weight_kg"/>
<property name="heightInMeters" column="per_height_m"/>
<many-to-one name="homeAddress" class="Address" column="home_address"/>
<property name="homeAddress" column="home_address"/>
<set name="addresses" lazy="true" inverse="true" batch-size="100" cascade="all-delete-orphan">
<key column="per_id"/>
<one-to-many class="Address"/>
</set>
</class>
</hibernate-mapping>
Address.hbm.xml
Code:
<hibernate-mapping package="net.vickerscraven.learning.hibernate">
<class name="Address" table="address">
<id column="address_id" type="integer">
<generator class="identity"/>
</id>
<natural-id mutable="false">
<many-to-one name="owner" class="Person" column="per_id"/>
<property name="tag" column="tag"/>
</natural-id>
<property name="address" column="address" not-null="true"/>
<property name="address2" column="address2" not-null="false"/>
<property name="city" column="city" not-null="true"/>
<property name="state" column="state" not-null="true"/>
<property name="zip" column="zip"/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
person = (Person)session.load(Person.class, new Integer(1));
System.out.println(person.getFirstName() + " " + person.getLastName());
if (person.getHomeAddress() != null) {
System.out.println("Found home address " + person.getHomeAddress().getAddress());
} else {
System.out.println("No home address for this person.");
}
Name and version of the database you are using:PostgreSQL 8.?
Debug level Hibernate log excerpt:Code:
INFO [main] - Hibernate 3.0.5
INFO [main] - hibernate.properties not found
INFO [main] - using CGLIB reflection optimizer
INFO [main] - using JDK 1.4 java.sql.Timestamp handling
INFO [main] - Mapping resource: net/vickerscraven/learning/hibernate/Address.hbm.xml
DEBUG [main] - trying to locate http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd in classpath under org/hibernate/
DEBUG [main] - found http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd in classpath
INFO [main] - Mapping class: net.vickerscraven.learning.hibernate.Address -> address
DEBUG [main] - Mapped property: owner -> per_id
DEBUG [main] - Mapped property: tag -> tag
DEBUG [main] - Mapped property: address -> address
DEBUG [main] - Mapped property: address2 -> address2
DEBUG [main] - Mapped property: city -> city
DEBUG [main] - Mapped property: state -> state
DEBUG [main] - Mapped property: zip -> zip
INFO [main] - Mapping resource: net/vickerscraven/learning/hibernate/Person.hbm.xml
DEBUG [main] - trying to locate http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd in classpath under org/hibernate/
DEBUG [main] - found http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd in classpath
INFO [main] - Mapping class: net.vickerscraven.learning.hibernate.Person -> person
DEBUG [main] - Mapped property: id -> per_id
DEBUG [main] - Mapped property: firstName -> per_first_name
DEBUG [main] - Mapped property: lastName -> per_last_name
DEBUG [main] - Mapped property: birthDate -> per_birth_date
DEBUG [main] - Mapped property: weightInKilograms -> per_weight_kg
DEBUG [main] - Mapped property: heightInMeters -> per_height_m
DEBUG [main] - Mapped property: homeAddress -> home_address
DEBUG [main] - Mapped property: homeAddress -> home_address
DEBUG [main] - Mapped property: addresses
INFO [main] - configuring from resource: /hibernate.cfg.xml
INFO [main] - Configuration resource: /hibernate.cfg.xml
DEBUG [main] - trying to locate http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd in classpath under org/hibernate/
DEBUG [main] - found http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd in classpath
DEBUG [main] - connection.driver_class=org.postgresql.Driver
DEBUG [main] - connection.url=jdbc:postgresql://nantahala/TESTDB
DEBUG [main] - connection.username=aaron
DEBUG [main] - connection.password=eagle212
DEBUG [main] - connection.pool_size=1
DEBUG [main] - dialect=org.hibernate.dialect.PostgreSQLDialect
DEBUG [main] - show_sql=true
INFO [main] - Configured SessionFactory: null
DEBUG [main] - properties: {hibernate.connection.password=eagle212, java.runtime.name=Java(TM) 2 Runtime Environment, Standard Edition, sun.boot.library.path=C:\Program Files\Java\jre1.5.0_02\bin, java.vm.version=1.5.0_02-b09, hibernate.connection.username=aaron, java.vm.vendor=Sun Microsystems Inc., java.vendor.url=http://java.sun.com/, path.separator=;, java.vm.name=Java HotSpot(TM) Client VM, file.encoding.pkg=sun.io, user.country=US, sun.os.patch.level=Service Pack 2, java.vm.specification.name=Java Virtual Machine Specification, user.dir=C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning, java.runtime.version=1.5.0_02-b09, java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment, java.endorsed.dirs=C:\Program Files\Java\jre1.5.0_02\lib\endorsed, os.arch=x86, java.io.tmpdir=C:\DOCUME~1\Aaron\LOCALS~1\Temp\, line.separator=
, java.vm.specification.vendor=Sun Microsystems Inc., user.variant=, os.name=Windows XP, sun.jnu.encoding=Cp1252, java.library.path=C:\Program Files\Java\jre1.5.0_02\bin;.;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\ATI Technologies\ATI.ACE\, java.specification.name=Java Platform API Specification, java.class.version=49.0, hibernate.connection.pool_size=1, sun.management.compiler=HotSpot Client Compiler, os.version=5.1, connection.password=eagle212, user.home=C:\Documents and Settings\Aaron, user.timezone=, connection.username=aaron, java.awt.printerjob=sun.awt.windows.WPrinterJob, file.encoding=Cp1252, java.specification.version=1.5, hibernate.connection.driver_class=org.postgresql.Driver, show_sql=true, user.name=Aaron, java.class.path=C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\ant-1.6.3.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\ant-antlr-1.6.3.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\ant-junit-1.6.3.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\ant-launcher-1.6.3.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\antlr-2.7.5H3.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\ant-swing-1.6.3.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\asm.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\asm-attrs.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\c3p0-0.8.5.2.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\cglib-2.1.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\cleanimports.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\commons-collections-2.1.1.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\commons-logging-1.0.4.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\commons-logging-1-0-3.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\concurrent-1.3.2.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\connector.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\dom4j-1.6.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\ehcache-1.1.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\hibernate3.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\ibatis-common-2.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\ibatis-sqlmap-2.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jaas.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jacc-1_0-fr.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jaxen-1.1-beta-4.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jboss-cache.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jboss-common.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jboss-jmx.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jboss-system.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jdbc2_0-stdext.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jgroups-2.2.7.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\jta.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\junit-3.8.1.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\log4j-1.2.9.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\logging-log4j-1.2.9.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\oscache-2.1.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\postgresql-8.0-310.jdbc2.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\proxool-0.8.3.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\swarmcache-1.0rc2.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\versioncheck.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\xerces-2.6.2.jar;C:\Documents and Settings\Aaron\My Documents\workspaces\swing_tutorials\Learning\xml-apis.jar, hibernate.show_sql=true, java.vm.specification.version=1.0, java.home=C:\Program Files\Java\jre1.5.0_02, sun.arch.data.model=32, hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect, hibernate.connection.url=jdbc:postgresql://nantahala/TESTDB, connection.pool_size=1, user.language=en, java.specification.vendor=Sun Microsystems Inc., awt.toolkit=sun.awt.windows.WToolkit, hibernate.cglib.use_reflection_optimizer=true, java.vm.info=mixed mode, java.version=1.5.0_02, java.ext.dirs=C:\Program Files\Java\jre1.5.0_02\lib\ext, sun.boot.class.path=C:\Program Files\Java\jre1.5.0_02\lib\rt.jar;C:\Program Files\Java\jre1.5.0_02\lib\i18n.jar;C:\Program Files\Java\jre1.5.0_02\lib\sunrsasign.jar;C:\Program Files\Java\jre1.5.0_02\lib\jsse.jar;C:\Program Files\Java\jre1.5.0_02\lib\jce.jar;C:\Program Files\Java\jre1.5.0_02\lib\charsets.jar;C:\Program Files\Java\jre1.5.0_02\classes, java.vendor=Sun Microsystems Inc., connection.driver_class=org.postgresql.Driver, file.separator=\, java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi, sun.io.unicode.encoding=UnicodeLittle, sun.cpu.endian=little, sun.desktop=windows, connection.url=jdbc:postgresql://nantahala/TESTDB, dialect=org.hibernate.dialect.PostgreSQLDialect, sun.cpu.isalist=}
DEBUG [main] - Preparing to build session factory with filters : {}
INFO [main] - processing extends queue
INFO [main] - processing collection mappings
DEBUG [main] - Second pass for collection: net.vickerscraven.learning.hibernate.Person.addresses
INFO [main] - Mapping collection: net.vickerscraven.learning.hibernate.Person.addresses -> address
DEBUG [main] - Mapped collection key: per_id, one-to-many: net.vickerscraven.learning.hibernate.Address
INFO [main] - processing association property references
INFO [main] - processing foreign key constraints
DEBUG [main] - resolving reference to class: net.vickerscraven.learning.hibernate.Person
DEBUG [main] - resolving reference to class: net.vickerscraven.learning.hibernate.Address
org.hibernate.MappingException: duplicate property mapping: homeAddress
at org.hibernate.mapping.PersistentClass.checkPropertyDuplication(PersistentClass.java:344)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:334)
at org.hibernate.mapping.RootClass.validate(RootClass.java:188)
at org.hibernate.cfg.Configuration.validate(Configuration.java:839)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1000)
at net.vickerscraven.learning.hibernate.TestHibernate.main(TestHibernate.java:32)