I have created the below OneToOne relationship with Hibernate and Kotlin. However, when I am Initializing Parent() it requires me to set child value as Parent(child=null) which is not desired. Only initializing child should require parent as Child(parent=Parent(...) and if I add both parent to child and child to parent, it creates an infinite loop. What it the right way to avoid that?
#Entity
class Parent(
#Id
#Column(nullable = false, updatable = false, columnDefinition = "uuid")
val id: UUID = UUID.randomUUID(),
#OneToOne(cascade = [CascadeType.ALL], mappedBy = "parent")
#JsonIgnore
#JoinColumn(name = "child_id", referencedColumnName = "id")
val child: Child?
)
#Entity
class Subscriber(
#Id
#Column(nullable = false, updatable = false, columnDefinition = "uuid")
val id: UUID = UUID.randomUUID(),
#OneToOne(cascade = [CascadeType.ALL], optional = false)
#JoinColumn(name = "id", columnDefinition = "uuid")
#MapsId
val parent: Parent
)
As parent and child are mapped one to one and you want to use #MapsId to not create another extra PK in child table. Now Child object will use parent_id has its own PK.
For Parent
#Entity
public class Parent {
#Id
#Column(nullable = false, updatable = false, columnDefinition = "uuid")
private UUID id = UUID.randomUUID();
public UUID getId() {
return id;
}
public Parent setId(UUID id) {
this.id = id;
return this;
}
}
Child
#Entity
public class Child {
#Id
#Column(nullable = false, updatable = false, columnDefinition = "uuid")
private UUID id = UUID.randomUUID();
#OneToOne(fetch = FetchType.LAZY)
#MapsId
private Parent parent;
public UUID getId() {
return id;
}
public Child setId(UUID id) {
this.id = id;
return this;
}
public Parent getParent() {
return parent;
}
public Child setParent(Parent parent) {
this.parent = parent;
return this;
}
}
Check below screenshot for how table will look in database.
Related
Should all child1 and child2 (depth 2) be deleted, when a parent gets deleted?
Database is Informix, constraints are created in the child tables. Deletion of parent is performed with JpaRepository.deleteById(parent.getId()), both do nothing and no error message occurs (show_sql just lists selects). Spring version is 5.3.19, spring-data-jpa 2.6.4.
Current example code:
#Entity
#Table(name = "parent_table")
public class Parent
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "parent", fetch = FetchType.EAGER)
private Set<Child1> children = new HashSet<>();
}
#Entity
#Table(name = "child1_table")
public class Child1
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "parentid", referencedColumnName = "id", nullable = false)
private Parent parent;
#OneToMany(orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "child1", fetch = FetchType.EAGER)
private Set<Child2> children = new HashSet<>();
}
#Entity
#Table(name = "child2_table")
public class Child2
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "child1id", referencedColumnName = "id", nullable = false)
private Child1 child1;
}
Update
added
#PreRemove
private void deleteChildren()
{
children.clear();
}
to Parent and Child1. Now children get deleted, but not the Parent.
In fact, Parent also had a parent and I had to remove this from it's Set too.
So the solution is:
Clear children Sets
#PreRemove
private void preRemove()
{
children.clear();
}
Remove the root entity from its parent in case it has a parent
#PreRemove
private void preRemove()
{
children.clear();
parentsParent.getParents().remove(this);
}
There are my classes:
Parent
#Entity
#NoArgsConstructor
#Data
#AllArgsConstructor
public class Parent {
#Id
private String id;
private String name;
private String ssn;
#Valid
#Type(type = "json")
#Column(columnDefinition = "jsonb")
#OneToMany(mappedBy="parent ", cascade = CascadeType.ALL)
private List<Child> children;
}
Child
#Entity
#NoArgsConstructor
#Data
#AllArgsConstructor
public class Child implements Serializable {
#Id
private String name;
private String parentId;
#Valid
#Type(type = "json")
#Column(columnDefinition = "jsonb")
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "parentId", referencedColumnName = "id", insertable = false, updatable = false)
private Parent parent;
}
Parent Mapper
#Mapper
public interface ParentMapper {
#Mapping(target = "id", expression = "java(setId(parent.getName(), parent.getSsn()))")
ParentEntity toParentEntity(CreateParent parent);
Parent toParent(ParentEntity parentEntity);
default String setId(String name, String ssn) {
if (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(ssn)) {
return String.format("%s+%s", name, ssn);
} else {
return null;
}
}
}
child mapper
#Mapper
public interface ChildMapper {
ChildEntity toChildEntity(CreateChild child, String parentId, String chaildName);
Child toChild(ChildEntity childEntity);
}
so there is an issue, creating and saving child object doesn't persist parent property of child object
Parent p = new Parent("somename","123456");
parentRepository.save(p);
Child c = new Child("somename");
c.setParentId(p.getId());
ChildEntity saved = childRepository.save(c);
saved.getParent() => returns null
ParentEntity savedParent = parentRepository.findById(p.getId());
savedParent.getChildren() => return null
Not sure what i done wrong ...
Two foreign keys act as primary key in entity for OneToOne, I'm getting error "Provided id of the wrong type for class ....."
When I tried to POST data, It's getting inserted correctly but GET is not working.
If I change OneToOne to OneToMany it is working for POST & GET both.
Request:
{
"items": [
{
"applicant": {
"guests": [
{
"seqNumber": 1,
"name": "name",
"gender": "gender"
}
]
}
}
]
}
Back Reference:
reservation.getItems().forEach(i -> {
i.setReservation(reservation);
i.getApplicant().setItem(i);
i.getApplicant().getGuests().forEach(g -> g.setApplicant(i.getApplicant()));
});
Reservation Entity:
#Entity
#Getter
#Setter
public class Reservation {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_RESERVATION", nullable = false, updatable = false)
private String reservationId;
#OneToMany(mappedBy = "reservation", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonManagedReference
private Set<Item> items = new HashSet<>();
}
Item Entity:
#Entity
#Getter
#Setter
#IdClass(Item.ItemKey.class)
public class Item {
#Id
#Column(name = "ID_ITEM_RESERVATION", nullable = false, updatable = false)
private long itemReservationId;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID_RESERVATION", referencedColumnName = "ID_RESERVATION", nullable = false, updatable = false)
#JsonBackReference
private Reservation reservation;
#OneToOne(mappedBy = "item", cascade = CascadeType.ALL)
#JsonManagedReference
private Applicant applicant;
#Data
static class ItemKey implements Serializable {
private Reservation reservation;
private long itemReservationId;
}
}
Applicant Entity:
#Entity
#Getter
#Setter
#IdClass(Applicant.ApplicantKey.class)
public class Applicant {
#Id
#OneToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ID_RESERVATION", referencedColumnName = "ID_RESERVATION", nullable = false, updatable = false),
#JoinColumn(name = "ID_ITEM_RESERVATION", referencedColumnName = "ID_ITEM_RESERVATION", nullable = false, updatable = false)
})
#JsonBackReference
private Item item;
#OneToMany(mappedBy = "applicant", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonManagedReference
private Set<Guest> guests = new HashSet<>();
#Data
static class ApplicantKey implements Serializable {
private Item item;
}
}
Guest Entity:
#Entity
#Getter
#Setter
#IdClass(Guest.GuestKey.class)
public class Guest {
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ID_RESERVATION", referencedColumnName = "ID_RESERVATION", nullable = false, updatable = false),
#JoinColumn(name = "ID_ITEM_RESERVATION", referencedColumnName = "ID_ITEM_RESERVATION", nullable = false, updatable = false)
})
#JsonBackReference
private Applicant applicant;
#Id
#Column(name = "S_NUMBER", nullable = false, updatable = false)
private Short seqNumber;
#Column(name = "N_NAME")
private String name;
#Column(name = "CD_GENDER")
private String gender;
#Data
static class GuestKey implements Serializable {
private Applicant applicant;
private Short seqNumber;
}
}
Expected output must be same as Request but getting error " ... Provided id of the wrong type for class ..."
Here is the code.
I have a parent object that looks like this:
#Entity
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(unique = true, nullable = false)
#RestResource(exported = false)
private int pk;
#Column(nullable = false)
private String title
#Column(nullable = false)
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private Set<Child> sentenceList;
}
And a child object that looks like this:
#Entity
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(unique = true, nullable = false)
#RestResource(exported = false)
private int pk;
#Column(nullable = false)
private String title
#ManyToOne
#JoinColumn(nullable=false)
private Parent parent;
}
What I want to do is POST to the parent's repository to create the parent and also create the embedded children. The POSTed JSON would look something like this:
{
"title": "Parent"
[
{
"title": "Child 1"
},
{
"title": "Child 2"
},
]
}
Is this possible with Spring Data REST? I currently get an error stating that the parent PK can't be null.
Thanks for any help!
I am trying to map the classic bi-directional oneToMany using eclipselink.
My problem is that when i want to insert a new 'child' i get
SQLIntegrityConstraintViolationException.
The database is described like this :
#Entity
#IdClass(KuponPK.class)
#Table(name = "KUPON", schema = "POST", catalog = "")
public class Kupon implements Serializable {
private Integer id;
private String spil;
private Collection<Kombination> kombinationList;
#OneToMany(mappedBy = "kupon", cascade = CascadeType.PERSIST)
public Collection<Kombination> getKombinationList() {
return kombinationList;
}
public class KuponPK implements Serializable {
private Integer id;
private String spil;
#Id
#Column(name = "ID", nullable = false, insertable = true, updatable = true, precision = 0)
public Integer getId() {
return id;
}
#Id
#Column(name = "SPIL", nullable = false, insertable = true, updatable = true, length = 5)
public String getSpil() {
return spil;
}
#Entity
#Table(name = "KOMBINATION", schema = "POST", catalog = "")
public class Kombination {
private Integer id;
private String sorteringOrden;
private Integer sorteringNr;
private Integer antalSpillede;
private BigDecimal odds;
private Kupon kupon;
#ManyToOne
#JoinColumns({#JoinColumn(name = "KUPON_ID", referencedColumnName = "ID", nullable = false, insertable=false, updatable=false),
#JoinColumn(name = "KUPON_SPIL", referencedColumnName = "SPIL", nullable = false, insertable=false, updatable=false)})
public Kupon getKupon() {
return kupon;
}
In my stateless session i have a Kupon object and i create a new Kombination where i set the Kupon and try to merge, but im getting
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("KOMBINATION"."KUPON_ID")
which is obvious since its part of primary key
I am setting the Kombination to Kupon and the Kupon to Kombination, but that doesnt make any difference
How can can i tell that the key is inside the Kupon object which im setting in the Kombination object ??