11

I am having trouble setting up jpa mappings for some entities. I have a parent entity defined like the following.

@Entity
@Table(name="EIF_INSTANCE_HDR")
public class InstanceEntity implements Serializable{

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(generator="eif_inst_gen")
    @SequenceGenerator(name="eif_inst_gen",sequenceName="EIF_INSTANCE_SEQ")
    @Column(name = "EAIH_ID")
    private Long eaihid;

    @Column(name = "EAD_ID")
    private Long eadid;

    @OneToMany(targetEntity=InstanceNotifyEntity.class, mappedBy="instance",fetch=FetchType.EAGER, cascade = CascadeType.ALL)
    private List<InstanceNotifyEntity> userDetails = new ArrayList<InstanceNotifyEntity>();

}

I then have a child entity w/ a composite key, and a foreign key to the primary key of this table as follows:

@Entity
@Table(name="EIF_INST_NOTIFIED")
public class InstanceNotifyEntity implements Serializable{

    private static final long serialVersionUID = 1L;
    
    @Id
    @ManyToOne
    @JoinColumn(name="EAIH_ID", referencedColumnName="EAIH_ID")
    private InstanceEntity instance;
    
    @Id
    @Column(name="USER_ID")
    private Long userId;

    @Column(name="COMMENT_TXT")
    private String commentText;

}

I know the child entity is incorrect, but I am unsure how to set this up to have a composite PK. I know I need to setup a PK class, but I am not sure how to do that when one field is a foreign key to the parent class. And once that is setup how would the parent reference the child entity?

Any help is appreciated.

Community
  • 1
  • 1
broschb
  • 4,976
  • 4
  • 35
  • 52

2 Answers2

15

This is governed by JPA 2 spec section 2.4.1, "Primary Keys Corresponding to Derived Identities". The section contains two examples directly applicable to your problem.

As described in the spec, there are two ways to represent the child entity's key in this case:

  • @IdClass
  • @EmbeddedId

Here's a rough sketch of the EmbeddedId way. I chose EmbeddedId arbitrarily, but the choice between IdClass and EmbeddedId is significant. You might choose differently.

// Child entity's composite primary key
@Embeddable
public class InstanceNotifyEntityId implements Serializable {
    Long eaihId;
    Long userId;
}

// Child entity
@Entity
@Table(name="EIF_INST_NOTIFIED")
public class InstanceNotifyEntity implements Serializable {
    @AttributeOverrides({
      @AttributeOverride(name="userId", column = @Column(name="USER_ID"))
      @AttributeOverride(name="eaihId", column = @Column(name="EAIH_ID"))
    })
    @EmbeddedId
    InstanceNotifyEntityId id;

    @MapsId("eaihId")
    @ManyToOne
    InstanceEntity instance;

    // ...
 }

The parent entity needs one change: the userDetails attribute mappedBy should be "id.eaihId". I think that's it, but I haven't used entities exactly like this before. Might have missed something... please post if you see errors.

ScottM
  • 620
  • 7
  • 20
Dan LaRocque
  • 5,123
  • 2
  • 22
  • 16
  • Thanks, this works for the most part. Unfortunately I am not using jpa 2.0 so the @MapsId annotation is not available. I have this working for inserts by removing the cascade relationship from the parent entity userDetails object. So I am required to insert each child element after persisting the parent element, but it is workable for now. – broschb Jul 26 '10 at 04:06
  • jpa 1.0 spec. Currently I am required to use jboss 4.2.3, my understanding is jpa 2.0 will not work on this app server, at least not without swapping out a bunch of libraries. – broschb Jul 29 '10 at 22:14
1

I was also facing the same issue and followed this answer but it is not saving the child entity with parent entity. Here is the changes which I made and it is working fine. Make below changes -

// Child entity's composite primary key class

public class InstanceNotifyEntityId implements Serializable {

    @Column(name = "USER_ID")
    Long userId;

    @JoinColumn(name = "EAIH_ID")
    @ManyToOne  
    InstanceEntity instance
}

// Child entity which contain composite primary key as a EmbeddedId, 
// no need to define any relationship here as we already define 
// the relationship in composite key class. 

@Entity
@Table(name = "EIF_INST_NOTIFIED")
public class InstanceNotifyEntity implements Serializable {

    @EmbeddedId
    InstanceNotifyEntityId id;
}


// Parent entity (parent entity mappedby should be your composite 
// key class instance.child class object which already have the 
// join column mapping with "EAID_ID")  

@Entity
@Table(name = "EIF_INSTANCE_HDR")
public class InstanceEntity implements Serializable {

    @OneToMany(mappedBy = "id.instance,fetch=FetchType.EAGER, cascade = CascadeType.ALL)
    private List<InstanceNotifyEntity> userDetails = new ArrayList<InstanceNotifyEntity>();
}

While saving the parent entity set the parent object into the composite key like id.setInstance(parent entire obj)

buræquete
  • 14,226
  • 4
  • 44
  • 89
Moni
  • 433
  • 3
  • 9