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

2

31

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>

Dhruv answered 26/3, 2015 at 12:17 Comment(0)
C
57

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.

Craniotomy answered 8/9, 2017 at 6:41 Comment(4)
This is the proper answer. JPA does not define explicit support for inheritance of embeddables. However Hibernate does support inheritance of embeddablesScroggins
Hit enter instead of shift+enter above :( This is the proper answer. JPA does not define explicit support for inheritance of embeddables. However Hibernate does support inheritance of embeddables using @MappedSuperclass to define its super-type. IMO we should add support for extending another embeddable as well - hibernate.atlassian.net/browse/HHH-12790Scroggins
wokrs in wilflfy 15Novelia
Thank you. By this instruction I got in JPA generated table of PostgreSQL database Mapped from Superclass columns with strange "Read-only: No Corresponding table column" DBeaver information. What does that mean?Brynhild
S
13

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.

Stamford answered 31/3, 2015 at 5:40 Comment(3)
Thank you saif for your reply but same class relation works fine in xml based configuration i need its alternate in annotation. I have added additional detail "Additional Detail"Dhruv
+1 because its a valid answer if it means there should not (generally) be an annotation for this availableHonorific
This answer is simply incorrect. As mentioned in my comment on the answer below, Hibernate does in fact "support inheritance of @Embeddable".Scroggins

© 2022 - 2024 — McMap. All rights reserved.