问题
I have the following model (ignoring irrelevant/obvious code, like setters and getters):
@Entity
public class Invoice {
@Id // sequence generated
private Long invoiceId;
@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "invoiceId", referencedColumnName = "invoiceId")
@OrderBy("id.itemNumber")
List<Item> items = new ArrayList<Item>();
}
@Entity
public class Item {
@EmbeddedId
private ItemPK id;
}
@Embeddable
public class ItemPK {
private Long invoiceId;
private Long itemNumber;
}
Can't change the DB structure, as it's a legacy DB :(
The itemNumber is basically an index that starts at zero.
If I take an existing Invoice and just remove the existing item and add 2 new items in the list, when trying to update the Invoice object I run into all sorts of problems:
If I leave the ItemPK null, I get: org.hibernate.TransientObjectException: object is an unsaved transient instance - save the transient instance before merging
If I try to fill the values of ItemPK myself (the id of the invoice and the index), I get: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session (there already is an invoice item in the DB and it has the invoice id and the index = 0, just like the first object in my new list of items).
If I try to leave the invoiceId null (in the ItemPK object), I get: java.sql.BatchUpdateException: ORA-01400: cannot insert NULL into ("Item"."invoiceId")
Is there anyway to let Hibernate/JPA handle this ? Or do I need to completely remove the association, defined the list as @Transient and just fill it and save it in my service classes ?
Thanks.
回答1:
You effectively have a bidirectional association here, since the invoiceId in the Item entity is in fact a foreign key to the Invoice. You should thus map the association as a bidirectional one, and use the @MapsId annotation. Its javadoc has an example.
来源:https://stackoverflow.com/questions/9162755/onetomany-relationship-with-composite-key