Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA Composite Key + Sequence

Is it possible in plain JPA or JPA+Hibernate extensions to declare a composite key, where an element of the composite key is a sequence?

This is my composite class:

@Embeddable
public class IntegrationEJBPk implements Serializable {

    //...


    @ManyToOne(cascade = {}, fetch = FetchType.EAGER)
    @JoinColumn(name = "APPLICATION")
    public ApplicationEJB getApplication() {
        return application;
    }


    @Column(name = "ENTITY", unique = false, nullable = false, insertable = true, updatable = true)
    public String getEntity() {
        return entity;
    }

    @GeneratedValue(strategy = GenerationType.AUTO, generator = "INTEGRATION_ID_GEN")
    @SequenceGenerator(name = "INTEGRATION_ID_GEN", sequenceName = "OMP_INTEGRATION_CANONICAL_SEQ")
    @Column(name = "CANONICAL_ID", unique = false, nullable = false, insertable = true, updatable = true)
    public String getCanonicalId() {
        return canonicalId;
    }

    @Column(name = "NATIVE_ID", unique = false, nullable = false, insertable = true, updatable = true)
    public String getNativeId() {
        return nativeId;
    }

    @Column(name = "NATIVE_KEY", unique = false, nullable = false, insertable = true, updatable = true)
    public String getNativeKey() {
        return nativeKey;
    }

    //...
}

I already supply the values for application, entity, nativeId and nativeKey. I want to construct an entity like the one below:

IntegrationEJB i1 = new IntegrationEJB();
i1.setIntegrationId(new IntegrationEJBPk());
i1.getIntegrationId().setApplication(app1);
i1.getIntegrationId().setEntity("Entity");
i1.getIntegrationId().setNativeId("Nid");
i1.getIntegrationId().setNativeKey("NK");

And when I call em.persist(i1), I want that the canonicalId is generated and the integration is inserted.

Is this possible? If so, what's the simple way? (I prefer not to use application-provided keys or native sql).

like image 467
Miguel Ping Avatar asked Oct 28 '08 11:10

Miguel Ping


People also ask

How can I get composite key in JPA with Hibernate?

The following rules apply for composite primary keys: The primary key class must be public and must have a public no-arg constructor. If property-based access is used, the properties of the primary key class must be public or protected. The primary key class must be serializable .

Can we use composite keys in hibernate?

A composite primary key is mapped using an Embeddable type in hibernate. We'll first create an Embeddable type called EmployeeIdentity containing the employeeId and companyId fields, and then create the Employee entity which will embed the EmployeeIdentity type.

How do you annotate composite keys in hibernate?

Using annotations. We can create a composite key using @Embeddable annotation. It is used in that POJO class which contains the information of all the primary keys. @Embeddable- It specifies a class whose objects are stored as an intrinsic part of an owing entity.


2 Answers

I believe that this is not possible with plain JPA.

like image 69
Miguel Ping Avatar answered Oct 19 '22 23:10

Miguel Ping


Using @GeneratedValue for composite PKs is not specified withi JPA 2 spec.

From the JPA spec:

11.1.17 GeneratedValue Annotation

The GeneratedValue annotation provides for the specification of generation strategies for the values of primary keys. The GeneratedValue annotation may be applied to a primary key property or field of an entity or mapped superclass in conjunction with the Id annotation.[97] The use of the GeneratedValue annotation is only required to be supported for simple primary keys. Use of the GeneratedValue annotation is not supported for derived primary keys.

Note that under a different scenario, you can have a parent entity with a simple PK (@Id) that uses @GeneratedValue, and then have a child entity that has a composite PK that includes the generated Id from the parent, plus another column.

  • Give the child a @ManyToOne relationship to the parent entity, so that it inherits the generated ID in a FK column.
  • Then give the child a composite PK, via @IdClass specified against the entity, plus two @Id columns within the entity.
@Entity
public class ParentEntity {
       @Id
       @GenerateValue(IDENTITY) // If using DB auto-increment or similar
       int id;

       // ...
}
@Entity
@IdClass(ChildId.class)
public class ChildEntity {
   // The child table will have a composite PK:
   // (parent_ID, child_name)
       @Id 
       @ManyToOne
       int parentEntity;
       @Id
       String childName;

       String favoriteColor;  // plus other columns

       // ...

}
// child Id attributes have the same name as the child entity
// however the types change to match the underlying PK attributes 
// (change ParentEntity to int)
 public class ChildId implements Serializable {
        int parentEntity;
        String childName;

        public ChildId() { //... }

        // Add extra constructor & remove setter methods so Id objects are immutable
        public ChildId(int parentEntity, String childName) { //... }


        public int getParentEntity() { //... }
        // make Id objects immutable:
        //  public void setParentEntity(int parentEntity) { //... }
        public String getChildName() { //... }
        //  public void setChildName(String childName) { //... }
}
like image 36
Glen Best Avatar answered Oct 20 '22 00:10

Glen Best