I’m having a problem creating a parent and child object and persisting them in one go to the database using JPA and hibernate. The parent class looking like this:
@Entity
@Table(name = "PUser")
public final class User {
@Id
@Column(name = "ID", unique = true, nullable = false, updatable = false)
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
}
The child object uses a compound key, one of fields being the ID of the parent:
@Entity
@Table(name = "PAttribute")
public final class Attribute {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "domain", column = @Column(name = "domain", nullable = false, length = 128)),
@AttributeOverride(name = "name", column = @Column(name = "name", nullable = false, length = 128)),
@AttributeOverride(name = "userid", column = @Column(name = "userid", nullable = false)) })
private AttributePk pk;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userid", nullable = false, insertable = false, updatable = false)
private User user;
}
The composite key class being:
@Embeddable
public class AttributePk implements java.io.Serializable {
private static final long serialVersionUID = -7003721226789641149L;
@Column(nullable = false, length = 128)
private String domain;
@Column(nullable = false, length = 128)
private String name;
@Column(nullable = false)
private long userid;
}
Now when I create a new User and add an Attachment, and then attempt to save the object graph
User user = new User("joe1.bloggs@ft.com", "xyz");
user.setScreenName("joe1bloggs");
user.addAttribute("domain", "name", 212);
target.saveAndFlush(user);
I get the exception
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`fta_portal_user/PAttribute`, CONSTRAINT `userId` FOREIGN KEY (`userid`) REFERENCES `PUser` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
Obviously the Attribute child object doesn’t have the ID of the user object set.
I know I can do the following, which works, but it seems odd that I can’t just create an object hierarchy and Hibernate work out how to set the IDs accordingly. I suspect that there’s no way round this as saveAndFlush() returns a new instance rather than just updating the input parameter version.
User user = new User("joe1.bloggs@ft.com", "xyz");
user.setScreenName("joe1bloggs");
// target is an JpaRepository intergafe
user = target.saveAndFlush(user);
user.addAttribute("domain", "name", 212);
target.saveAndFlush(user);
Anyone have any ideas or is it just a case of living with it?
Thanks
Nick
EDIT: You can get this to work by adding the @MapsId annotation to the child class (thanks to axtavt’s reply). i.e.
@MapsId("userId")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId", nullable = false, insertable = false, updatable = false)
private User user;
Have you tried to map it as follows:
As far as I understand in this case
useridfield ofAttributePkshould be populated with the id ofuserautomatically.