Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate @Embeddable class which extends another @Embeddable class, Properties not found for @OneToMany mapping

We are translating old xml based configuration to Annotation based configuration

Situation

There is a class which is annotated as @Embeddable(ParentPk.java), another class extends this class which is @Embeddable(ChildPk.java), this ChildPk.java is used as composite primary key in SomeOwnerClass.java, Which have foreign relation with another class SomeChildTable.java and tends to use properties col1 and col2 which are available in parent class of ChildPk.java but when query is executed hibernate does not finds col1 and col2 rather if I copy col1 and col2 in ChildPk.java from parent class every thing works fine.

Below is code snippet of SomeOwnerClass.java which refers to col1 and col2

>  @OneToMany(orphanRemoval = true, fetch=FetchType.EAGER)
>        @Cascade(value = {CascadeType.ALL,CascadeType.SAVE_UPDATE})
>        @Fetch(FetchMode.JOIN)
>        @JoinColumns({
>        @JoinColumn(name="COL_1",insertable=false,updatable=false,referencedColumnName="COL_1"),
>        @JoinColumn(name="COL_2",insertable=false,updatable=false,referencedColumnName="COL_2"),
>        @JoinColumn(name="COL_3",insertable=false,updatable=false,referencedColumnName="COL_3"),
>     })    private Set<SomeChildTable> collection = new
> HashSet<SomeChildTable>();

Any solution for this situation?

ParentPk.java

 @Embeddable
    public class ParentPk implements Serializable  {

        @Column(name="COL_1")
        private String col1;

        @Column(ame="COL_2")
        private String col2;

    }

ChildPk.java

@Embeddable
public class ChildPk extends ParentPk implements Serializable  {

    @Column(name="COL_3")
    private String col3;
}

SomeOwnerClass.java

@Entity
@Table(name="FOO")
public class SomeOwnerClass implements Serializable  {

    @EmbeddedId
       @AttributeOverrides({@AttributeOverride(name="col1", column=@Column(name="COL_1",length=38))})
        private ChildPk childPk = new ChildPk();

         @OneToMany(orphanRemoval = true, fetch=FetchType.EAGER)
         @Cascade(value = {CascadeType.ALL,CascadeType.SAVE_UPDATE})
         @Fetch(FetchMode.JOIN)
         @JoinColumns({
         @JoinColumn(name="COL_1",insertable=false,updatable=false,referencedColumnName="COL_1"),
         @JoinColumn(name="COL_2",insertable=false,updatable=false,referencedColumnName="COL_2"),
         @JoinColumn(name="COL_3",insertable=false,updatable=false,referencedColumnName="COL_3"),
      })
    private Set<SomeChildTable> collection = new HashSet<SomeChildTable>();
}

Exception

org.hibernate.MappingException: Unable to find column with logical name: COL_1 in SomeOwnerClass
    at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:587)
    at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:258)
    at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1451)
    at org.hibernate.cfg.annotations.CollectionBinder.bindOneToManySecondPass(CollectionBinder.java:864)
    at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:779)
    at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:728)
    at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:70)
    at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1695)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1424)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
    at com.foo.mypackage.ParentHibernateUtil.initiateSessionFactory(ParentHibernateUtil.java:112)
    at com.foo.mypackage.ParentHibernateUtil.getSessionFactory(ParentHibernateUtil.java:131)
    at com.foo.mypackage.GenericHibernateDAO.getSession(GenericHibernateDAO.java:36)
    at com.foo.mypackage.GenericHibernateDAO.beginTransaction(GenericHibernateDAO.java:63)
    at com.foo.mypackage.MarsTest.main(MyTest.java:22)

Additional Detail I have tried to map xml based configuration to annotation based configuration below is old xml based configuration which works fine in term of inheritence.

ChildPk.java converted to @Embedable which extends ParentPk.java

<class name="SomeOwnerClassDetail" table="FOO_DETAIL">

        <composite-id class="ChildPk"
            name="childPk">
            <key-property name="col1" column="COL_1"  type="java.lang.Long"/>
            <key-property name="col2" column="COL_2" length="32"/>
            <key-property name="col3" column="COL_3" length="3"/>
        </composite-id>
    </class>

in above mapping col1 and col2 are inherited from ParentPk.java which are accessible if ChildPk is used as foreign key in SomeOwnerClass.java in xml mapping but not in annotated mapping.

I can't change structure of my class as it is legacy application.

SomeOwnerClass.java

<set name="someDetailKey" cascade="all,delete-orphan,save-update" lazy="false" fetch="join"  > 
        <key foreign-key="FOO_Foreign_Key" >
            <column name="COL_1"/>
            <column name="COL_2"/>
            <column name="COL_3"/>
        </key>
        <one-to-many class="ChildPk" />
    </set>

like image 992
Yahya Arshad Avatar asked Mar 26 '15 12:03

Yahya Arshad


2 Answers

You can implement inheritance between @Embeddable classes. You just have to annotate the parent class with @MappedSuperclass too.

So, e.g.:

@Embeddable
@MappedSuperclass
public class Parent {
    @Basic
    private String parentProperty;

    // ... getters/setters
}

@Embeddable
public class Child extends Parent {
    @Basic
    private String childProperty;

    // ... getters/setters
}

This way Hibernate (tested with 5.x) will map both parentProperty and childProperty correctly in the Child class.

like image 116
mihu86 Avatar answered Oct 29 '22 15:10

mihu86


Hibernate doesn't support inheritance of @Embeddable component:

An embeddable object cannot be directly persisted, or queried, it can only be persisted or queried in the context of its parent. An embeddable object does not have an id or table. The JPA spec does not support embeddable objects having inheritance, although some JPA providers may allow this.

— Java_Persistence/Embeddables.

The JPA spec does not support embeddable objects having inheritance
So you cannot make use of Inheritance in @Embeddable.

You can try to get it done by having the parent id as a property of the child id.

like image 35
Saif Avatar answered Oct 29 '22 14:10

Saif