Search code examples
javaentity-frameworkhibernatejpaeclipselink

Force to do flush to get new Primary key ID to store EmbeddedId


We are using JPA and we are using EmbeddedId in one of the Entity.

Tables are as bellow :

Role:
+-----------------------------+
| roleId | name | discription |
+-----------------------------+


Rights:
+-----------------------------+
| rightId | name | discription|
+-----------------------------+

rightrole
+--------------------------------------+
| roleId | rightId | some other column |
+--------------------------------------+

Entity for role table is:

@Entity
@Table(name = "role")
public class Role {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @NotNull
    @Column(nullable = false)
    private Long roleID;


    @OneToMany(cascade = CascadeType.ALL, mappedBy = "role", fetch = FetchType.LAZY)
    private List<RightRole> rightRoleList;

.......
}

Entity for rightrole table is:

    @Entity
    @Table(name = "rightrole")
    public class RightRole extends BaseEntity<RightRolePK> {

        private static final long serialVersionUID = 1L;

        @EmbeddedId
        protected RightRolePK rightRolePK;


        @JoinColumn(name = "roleID", referencedColumnName = "roleID", insertable = false, updatable = false)
        @ManyToOne(fetch = FetchType.LAZY)
        private Role role;

        @JoinColumn(name = "rightID", referencedColumnName = "rightID", insertable = false, updatable = false)
        @ManyToOne(fetch = FetchType.LAZY)
        private Right right;

        ......
     }


    @Embeddable
    public class RightRolePK implements Serializable {
    private static final long serialVersionUID = 1L;

      @Basic(optional = false)
      @NotNull
      @Column(nullable = false)
      private long roleID;

      @Basic(optional = false)
      @NotNull
      @Column(nullable = false)
     private long rightID;

   .....

}

My problem is whenever I want to create new role with rights then first I have to store(persist) role object and then I have to do flush to get newly generated id for role. then and then i can put it in rightrole entity's object.

Is there any way by that i can set rightrole list in role object and persist it in one go.

This flush casing us performance bottle neck because for bulk insert we have to persist single single object.

we are using Auto Generated primary key.


Solution

  • JPA 2.0 allows derived IDs, an expanded to support this better by adding @MapsId. Keeping everything else the same but using:

    @Entity
    @Table(name = "rightrole")
    public class RightRole extends BaseEntity<RightRolePK> {
    
        private static final long serialVersionUID = 1L;
    
        @EmbeddedId
        protected RightRolePK rightRolePK;
    
        @MapsId("roleID")
        @JoinColumn(name = "roleID", referencedColumnName = "roleID")
        @ManyToOne(fetch = FetchType.LAZY)
        private Role role;
    
        @MapsId("rightID")
        @JoinColumn(name = "rightID", referencedColumnName = "rightID", insertable = false, updatable = false)
        @ManyToOne(fetch = FetchType.LAZY)
        private Right right;
    
        ......
     }
    

    This will tell JPA that the value within the roleID and rightID attributes in your PK class are controlled by the relationship mapping, and it will set it after synchronizing to the database with the primary key value from the reference. You just need to be sure you set the relationship before calling persist, as it doesn't have a primary key otherwise.

    This works even if the referenced object is also composite. Something that needs to reference RightRole would use RightRolePK though instead of a Long value:

    @Entity
    @Table(name = "wrong_right_role")
    public class WrongRightRole{
        @EmbeddedId
        WrongRightRoleId wrongRightRoleId;
    
        @MapsId("rightRoleID")
        @JoinColumns({
            @JoinColumn(name = "roleID", referencedColumnName = "roleID"),
            @JoinColumn(name = "rightID", referencedColumnName = "rightID")
        })
        RightRole rightRole;
    
    }
    
    @Embeddable
    public class WrongRightRolePK implements Serializable {
    private static final long serialVersionUID = 1L;
    
      private RightRoleID rightRoleID;
      .....
    }
    

    JPA also allows marking the right and role mappings with the @ID annotation, allowing you to remove the rightRolePK embeddedId from within the object, and use it as a primary key class instead.