0

I have a superclass (annotated with the @MappedSuperclass strategy) and 2 persistable subclasses: SubClass1 and SubClass2. This superclass contains a map of objects of type "EmbeddedObject". The problem is that when I instantiate an entity of type SubClass1 and try to persist it, I get a the following error:

Referential integrity constraint violation: "FKN0P0Y5R3MEM881KR8U3HDHYGS: PUBLIC.EMBEDDEDOBJECTSMAP_TESTOBJECT_MAPPING FOREIGN KEY(EMBEDDEDOBJECTSMAP_SUPERCLASSID) REFERENCES PUBLIC.SUBCLASS2(SUPERCLASSID) (1)"; SQL statement: insert into EmbeddedObjectsMap_TestObject_mapping (EmbeddedObjectsMap_SuperClassID, embeddedObjectsMap_KEY, EmbeddedObject_id) values (?, ?, ?) [23506-200]

My understanding is that, by building the corresponding row in the join table, Hibernate looks for a "SubClass2" type entity (instead of SubClass1 type), for an unknown reason.

Hint: I noticed that, if I change entity declaration's order in the hibernat.cfg.xml file, swapping the 2 lines as follows:

Before:

<mapping class="fr.blablabla.testpersistingmapinmappedsuperclasscontext.SubClass1" />
<mapping class="fr.blablabla.testpersistingmapinmappedsuperclasscontext.SubClass2" />

After:

<mapping class="fr.blablabla.testpersistingmapinmappedsuperclasscontext.SubClass2" />
<mapping class="fr.blablabla.testpersistingmapinmappedsuperclasscontext.SubClass1" />
    

... the error proves to disappear (but persisting a "SubClass2" entity will fail of course).

Here is my code:

The superclass:

package fr.blablabla.testpersistingmapinmappedsuperclasscontext;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.MapKeyColumn;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToMany;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

@MappedSuperclass
public class SuperClass {

    public SuperClass() {
        // TODO Auto-generated constructor stub
    }
    protected Long superClassID;
    
    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    @Column(name = "SuperClassID")
    public Long getSuperClassID() {
        return superClassID;
    }

    public void setSuperClassID(final Long superClassID) {
        this.superClassID = superClassID;
    }

    
    private Map<Long, EmbeddedObject> embeddedObjectsMap= new HashMap<Long, EmbeddedObject>();

@OneToMany (cascade = CascadeType.ALL)

        @Fetch(FetchMode.JOIN)
        @JoinTable(
                name = "EmbeddedObjectsMap_TestObject_mapping", 
    
                joinColumns = {@JoinColumn(name = "EmbeddedObjectsMap_SuperClassID", referencedColumnName = "superClassID")},
                inverseJoinColumns = {@JoinColumn(name = "EmbeddedObject_id", referencedColumnName = "embeddedObjectID")})
        @MapKeyColumn
    public Map<Long, EmbeddedObject> getEmbeddedObjectsMap() {
        return (Map<Long, EmbeddedObject>) embeddedObjectsMap;
    }

    public void setEmbeddedObjectsMap(Map<Long, EmbeddedObject> embeddedObjectsMap) {
        this.embeddedObjectsMap=embeddedObjectsMap;
    }
}


The 2 subclasses Subclass1 and SubClass2 are identical:

package fr.blablabla.testpersistingmapinmappedsuperclasscontext;
import javax.persistence.Entity;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity

@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

public class SubClass1 extends SuperClass {

    public SubClass1() {
        // TODO Auto-generated constructor stub
    }

}

The object embedded in the hashmap is just a standard entity:

package fr.blablabla.testpersistingmapinmappedsuperclasscontext;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class EmbeddedObject {

    public EmbeddedObject() {
        // TODO Auto-generated constructor stub
    }
    
    protected Long embeddedObjectID;
    
    @Id
    @GeneratedValue //(strategy = GenerationType.IDENTITY)
    public Long getEmbeddedObjectID() {
        return embeddedObjectID;
    }

    public void setEmbeddedObjectID(Long embeddedObjectID) {
        this.embeddedObjectID = embeddedObjectID;
    }
}

And finally, the main class:

package fr.blablabla.testpersistingmapinmappedsuperclasscontext;

import java.util.Map;

import org.hibernate.Session;
import org.hibernate.Transaction;

public class TestPersistingMap {

    public TestPersistingMap() {
        // TODO Auto-generated constructor stub
    }
    public static void main(String[] args) {
        SuperClass type1SubClass= new SubClass1();
        Transaction transaction = null;
        try (Session session = HibernateUtilTest.getSessionFactory().getCurrentSession()) {
        // start a transaction
        transaction = session.beginTransaction();

        EmbeddedObject embeddedObject1 = new EmbeddedObject();  

        Map<Long, EmbeddedObject> map =type1SubClass.getEmbeddedObjectsMap();

        map.put(1L, (EmbeddedObject) embeddedObject1);      
    
        session.saveOrUpdate(type1SubClass);
        // commit transaction
        transaction.commit();
        System.out.println("entity persisted:"+ type1SubClass.toString());
    } catch (Exception e) {
        e.printStackTrace();
        if (transaction != null) {
            transaction.rollback();
        }
      }
          System.out.println("Fin du programme TestpersistingMap");
    }

}

Any help highly appreciated !

  • Such setup is not going to work, if `SubClass1` and `SubClass2` do not share common db table, it is not possible to create foreign key constraint – Andrey B. Panfilov Jul 07 '22 at 17:41
  • @Andrey Thank you for this clarification, so if I want to keep seperate tables for subclasses (for performance reasons), the only option would be to ad an embeddedObjectsMap in each subClasse, correct ? – CaiusCornelius Jul 10 '22 at 15:46
  • yep, or do not use FK in this particular case – Andrey B. Panfilov Jul 10 '22 at 16:06
  • OK, so my understanding is as follows: since SubClass1 and SubClass2 contain a map, Hibernate will generate one "join table" for each of these 2 class. These seperate join tables cannot refer to the same table (the table corresponding to the class of the elements in the map): this is the principle of the FK constraint. So finally I gave up trying to keep completely separate the 2 SubClass tables , and changed from @MappedSuperclass to the joined table inheritance strategy: @Inheritance(strategy = InheritanceType.JOINED). – CaiusCornelius Sep 16 '22 at 12:37

0 Answers0