All,
I have an entity that includes embeddable objects with @AttributeOverrides that change the column names. The same entity needs to have a collection of child objects that are joined to this class based on the columns that have now been overridden with new names. When I use JoinColumns({@JoinColumn...}) to try to map these I get mapping exceptions. when I eliminate the embeddable object in favor of a plain column, the join seems to work, but when I have that extra hop in the object model, it does not behave well.
I have distilled the issue into the attached test case to see if anyone can tell me what I'm doing wrong or if this is a bug in hibernate. If it is a bug, can anyone think of a workaround that does not involve changing the object model?
Thanks!
-Ron
Code:
package eg.hibernate;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import java.util.Properties;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.Test;
public class JoinColumnsExampleTest
{
@Test
public void test() throws IOException
{
AnnotationConfiguration cfg = new AnnotationConfiguration();
Properties properties = new Properties();
properties.load( new StringReader( ""
+ "hibernate.connection.driver_class=oracle.jdbc.OracleDriver\n"
+ "hibernate.connection.url=jdbc:oracle:thin:@localhost:1521:XE\n"
+ "hibernate.connection.username=scott\n"
+ "hibernate.connection.password=tiger\n"
+ "hibernate.dialect=org.hibernate.dialect.OracleDialect\n" + "" ) );
cfg.setProperties( properties );
cfg.addAnnotatedClass( TestClassParent.class );
cfg.addAnnotatedClass( TestClassChild.class );
cfg.addAnnotatedClass( TestClassEmbeddedSuper.class );
cfg.addAnnotatedClass( TestClassEmbedded1.class );
cfg.addAnnotatedClass( TestClassEmbedded2.class );
assertNotNull( cfg.buildSessionFactory() );
}
// //////////////////
// Test Classes
// //////////////////
@Entity
@Table(name = "T_PARENT")
public class TestClassParent
{
@Id
@Column(name = "ID")
private Long databaseId;
@Embedded
@AttributeOverrides( { @AttributeOverride(name = "value", column = @Column(name = "FIELD_1")) })
private TestClassEmbedded1 field1;
@Embedded
@AttributeOverrides( { @AttributeOverride(name = "value", column = @Column(name = "FIELD_2")) })
private TestClassEmbedded2 field2;
////////////////////////////////////////////////////
// If these are put in in place of the AttributeOverrides above, the mapping works!
//
// @Column(name="FIELD_1")
// private String val1;
//
// @Column(name="FIELD_2")
// private String val2;
//
@OneToMany
@JoinColumns( {
@JoinColumn(name = "FIELD_1", referencedColumnName = "FIELD_1", insertable = false, updatable = false),
@JoinColumn(name = "FIELD_2", referencedColumnName = "FIELD_2", insertable = false, updatable = false), })
private List<TestClassChild> children;
public void setField1( TestClassEmbedded1 field1 )
{
this.field1 = field1;
}
public TestClassEmbedded1 getField1()
{
return field1;
}
public void setField2( TestClassEmbedded2 field2 )
{
this.field2 = field2;
}
public TestClassEmbedded2 getField2()
{
return field2;
}
public void setDatabaseId( Long databaseId )
{
this.databaseId = databaseId;
}
public Long getDatabaseId()
{
return databaseId;
}
public void setChildren( List<TestClassChild> children )
{
this.children = children;
}
public List<TestClassChild> getChildren()
{
return children;
}
}
@Entity
@Table(name = "T_CHILD")
public class TestClassChild
{
@Id
@Column(name = "ID")
private Long databaseId;
@ManyToOne
private TestClassParent parent;
public void setDatabaseId( Long databaseId )
{
this.databaseId = databaseId;
}
public Long getDatabaseId()
{
return databaseId;
}
public void setParent( TestClassParent parent )
{
this.parent = parent;
}
public TestClassParent getParent()
{
return parent;
}
}
@Embeddable
public class TestClassEmbeddedSuper
{
@Column(name = "VALUE")
private String value;
public void setValue( String value )
{
this.value = value;
}
public String getValue()
{
return value;
}
}
@AttributeOverrides({@AttributeOverride(name="value", column=@Column(name="FIELD_1"))})
public class TestClassEmbedded1 extends TestClassEmbeddedSuper
{
}
@AttributeOverrides({@AttributeOverride(name="value", column=@Column(name="FIELD_2"))})
public class TestClassEmbedded2 extends TestClassEmbeddedSuper
{
}
}