I’ve got Parent – Child relationship OneToOne, but two of them. Annotations are not good but it produces good DB schema, yet code is not working. If I try to save Parent instance, Hibernate at first tries to save child1 and child2 – but it breaks FK defined in Child -> because owner doesn’t exist yet in DB…So I need to save Parent and then child1, and child2.
If I could do that it doesn’t help, because when I try to load Parent, Hibernate will not know which record in Child table belongs to child1 or child2…So in this case I would need to specify one condition in join for child1 something like “where type = 1” and for child2 “where type = 2″…
Just to clarify: in Child table there will be zero or one child for one Parent with ChildType.A (always child1) and zero or one child with ChildType.B (always child2).
I need to save xml which looks like this:
<parent id="" oid="">
<child1 (and other attributes)>
<child2 (and other attributes)>
<parent>
Both child1 and child2 elements are the same type therefore are type of Child in java classes. Only difference is element name (in java I differentiate them with ChildType). Only identification for children are id and oid attributes from parent. They points to another Parent hence target in Child.
I need to change annotations somehow to get this working…Do you guys have some ideas, because I’m really stuck???
Parent.java
public class Parent {
private String oid
private Long id;
private Child child1;
private Child child2;
@Id
@GeneratedValue(generator = "IdGenerator")
@GenericGenerator(name = "IdGenerator", strategy = "com.example.IdGenerator")
@Column(name = "id")
public Long getId() {
return id;
}
@Id
@GeneratedValue(generator = "OidGenerator")
@GenericGenerator(name = "OidGenerator", strategy = "com.example.OidGenerator")
@Column(name = "oid", nullable = false, updatable = false, length = 36)
public String getOid() {
return oid;
}
@OneToOne(optional = true, fetch = FetchType.EAGER)
@Cascade({org.hibernate.annotations.CascadeType.ALL})
public Child getChild1() {
return child1;
}
@OneToOne(optional = true, fetch = FetchType.EAGER)
@Cascade({org.hibernate.annotations.CascadeType.ALL})
public Child getChild2() {
return child2;
}
}
Child.java
public class Child {
private Parent owner;
private String ownerOid;
private Long ownerId;
private ChildType type;
private Parent target;
@MapsId("owner")
@ManyToOne(fetch = FetchType.LAZY)
@PrimaryKeyJoinColumns({
@PrimaryKeyJoinColumn(name = "owner_oid", referencedColumnName = "oid"),
@PrimaryKeyJoinColumn(name = "owner_id", referencedColumnName = "id")
})
public Parent getOwner() {
return owner;
}
@MapsId("target")
@ManyToOne(fetch = FetchType.LAZY)
@PrimaryKeyJoinColumns({
@PrimaryKeyJoinColumn(name = "target_oid", referencedColumnName = "oid"),
@PrimaryKeyJoinColumn(name = "target_id", referencedColumnName = "id")
})
public Parent getTarget() {
return target;
}
@Id
@Column(name = "owner_id")
public Long getOwnerId() {
if (ownerId == null && owner != null) {
ownerId = owner.getId();
}
return ownerId;
}
@Id
@Column(name = "owner_oid", length = 36)
public String getOwnerOid() {
if (ownerOid == null && owner != null) {
ownerOid = owner.getOid();
}
return ownerOid;
}
@Id
@Column(name = "target_id")
public Long getTargetId() {
if (targetId == null && target != null) {
targetId = target.getId();
}
return targetId;
}
@Id
@Column(name = "target_oid", length = 36)
public String getTargetOid() {
if (targetOid == null && target != null) {
targetOid = target.getOid();
}
if (targetOid == null) {
targetOid = "";
}
return targetOid;
}
@Id
@Enumerated(EnumType.ORDINAL)
public ChildType getType() {
if (type == null) {
return ChildType.A;
}
return type;
}
}
ChildType.java
public enum ChildType {
A, B;
}
I also tried to use mappedBy approach mappedBy approach but there are still problems with loading – I can’t tell hibernate which child record belogs to which child class member variable.
there are too many things I don’t quite get in your solution to give a good answer but just some thoughts:
Consider using inheritance instead of ChildType enum. So you would have ChildA and ChildB extending Child.
That way you Parent can have:
Instead of having a composite primary key, I would consider using a unique auto generated key and then add a unique constraint on on the other id and oid fields. It should make the child parent relationships easier and you can have different parent implementation for ChildA and ChildB:
And
And in Child just:
Now the whole Parent/Owner/Target thing I still didn’t quite grasp.