Uploaded image for project: 'Hibernate ORM'
  1. HHH-11714

Entities with InheritanceType.SINGLE_TABLE and SecondaryTable are not being saved correctly

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 5.2.9
    • Fix Version/s: 5.2.11, 5.1.12
    • Component/s: hibernate-core
    • Labels:
      None
    • Environment:
      Spring-data-jpa version 1.11.1.release
    • Bug Testcase Reminder (view):

      Bug reports should generally be accompanied by a test case!

    • Worked in:
    • Last commented by a user?:
      true
    • Sprint:

      Description

      A problem has been introduced since hibernate 5.1.3 whereby entities with InheritanceType.SINGLE_TABLE and SecondaryTable are not being saved properly any more. Some classes exist only in the top table, others use additional tables for specific attributes, so we are combining Single and Joined table inheritance, using SecondaryTable for the join.

      We are using spring-data-jpa version 1.11.1.release.

      In our application we have a base SHAPE table and sub tables that store specific attributes for some other shape types
      such as circles. In the case of a circle the table is SHAPE_CIRCLE and it contains the circle centre.

      The shapes are wrapped further into a top level class which is used to save a collection of shapes in one go.

      An outline of the entities is as follows:

      ShapeEntity.java
      @Entity
      @Table(name = "SHAPE")
      @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
      @DiscriminatorColumn(name = "SHAPE_TYPE", discriminatorType = DiscriminatorType.STRING)
      
      public class ShapeEntity {
      
        @Id
        @SequenceGenerator(name = "SHAPE_ID_GENERATOR", sequenceName = "SHAPE_SEQ", allocationSize = 1)
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SHAPE_ID_GENERATOR")
        @Column(name = "SHAPE_ID", insertable = false, updatable = false)
        private Long id;
      
        .... other attributes ...
      
      ShapePolygonEntity.java
      @Entity
      @DiscriminatorValue("POLYGON")
      public class ShapePolygonEntity extends ShapeEntity {
      
      // The polygon is stored entirely in the SHAPE table.
      }
      
      ShapeCircleEntity.java
      @Entity
      @DiscriminatorValue("CIRCLE")
      @SecondaryTable(name = "SHAPE_CIRCLE", pkJoinColumns = @PrimaryKeyJoinColumn(name = "SHAPE_ID"))
      public class ShapeCircleEntity extends ShapeEntity {
      
        @Column(table = "SHAPE_CIRCLE")
        private Geometry centre;
        }
      
      GeographicArea.java
      @Entity
      @Table(name="GEOGRAPHIC_AREA")
      public class GeographicArea {
        ...
        /// The reference to the top level class.
        @ManyToOne
        @JoinColumn(name = "TOP_LEVEL_ID")
        private TopLevelEntity topLevel;
      
        // The reference to the shape.
        @OneToOne(cascade = CascadeType.ALL)
        @JoinColumn(name = "SHAPE_ID")
        private ShapeEntity shape;
        ...
      
      TopLevel.java
      @Entity
      @Table (name="TOP_LEVEL”)
      public class TopLevel {
      
        ....
      
        @OneToMany(mappedBy = "topLevel", cascade = {CascadeType.ALL},  orphanRemoval = true)
        private List<GeographicArea> geographicAreas;
        
        ....
       } 
      

      When TopLevel is saved, if a ShapePolygonEntity is in the list before a ShapeCircleEntity then inserts into the SHAPE table
      are executed for the polygon but inserts are not generated in the SHAPE and SHAPE_CIRCLE table for the circle.

      {
        top = new TopLevelEntity ();
        top. geographicAreas.add (new ShapePolygonEntity());
        top. geographicAreas.add (new ShapeCircleEntity());
      …
        topRepository.save (top);
      }
      
      Sql > insert into top_level …;
      Sql> insert into shape (for polygon);
      Sql> insert into geographic_area (for polygon);
      Sql> insert into geographic_area (for circle); - fails with FK violation, as the Shape doesn’t exist.
      

      If the ShapeCircleEntity goes before the ShapePolygonEntity then inserts
      are generated in the SHAPE table for the polygon and inserts are generated in the SHAPE and SHAPE_CIRCLE table for the circle.

      {
        top = new TopLevelEntity ();
        top. geographicAreas.add (new ShapeCircleEntity());
        top. geographicAreas.add (new ShapePolygonEntity());
      …
        topRepository.save (top);
      }
      
      Sql > insert into top_level …;
      Sql> insert into shape (for circle);
      Sql> insert into shape_circle (additional circle attributes);
      Sql> insert into shape (for polygon);
      Sql> insert into geographic_area (for circle);
      Sql> insert into geographic_area (for polygon);
      

      This used to work either way in version 5.1.3.

        Attachments

          Issue links

            Activity

              People

              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: