I'm looking for how to solve a recursion and bidiretional onetoone relationship in my Branch object:
#Entity
#Table("BRANCH")
public class Branch {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#OneToOne
#JoinColumn(name = "id")
private Branch parent;
#OneToOne(mappedBy = "parent")
#JoinColumn(name = "parent_id")
private Branch child;
//Getters and Setters
}
Is it an accepted pattern?
Right way of bidirectional #OneToOne mapping with self reference:
#Entity
#Table("BRANCH")
public class Branch {
#OneToOne
#JoinColumn(name = "parent_id")
private Branch parent;
#OneToOne(mappedBy = "parent")
private Branch child;
this is ancestor for object in child field
this is descendant for object in parent field
Hierarchy is: parent > this > child
You do not require two foreign keys, single
foreign key in the owning side of the relationship is sufficient. In
JPA the inverse OneToOne must use the mappedBy attribute.
https://en.wikibooks.org/wiki/Java_Persistence/OneToOne#Inverse_Relationships,_Target_Foreign_Keys_and_Mapped_By
Related
I have a parent table, and I am trying to create a #OneToMany relationship between the parent and child tables (e.g. one parent table can be associated with several child tables).
Parent.java
#Entity
#Table(name = "parent")
public class Threat {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long parentId;
#Column(name = "name")
private String parentName;
}
Child.java
#Entity
#Table(name = "child")
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long childId;
#Column(name = "parent_id")
private long parentId;
#Column(name = "name")
private String childName;
#Column(name = "age")
private Integer childAge;
}
I am having trouble figuring out how to do this given the fact I need to join the primary key of the parent table (parent.id) to a column in the child table that is not the primary key (child.parent_id). Ideally, when I return a Parent object, I would like both the parent id and the list of children displayed, so the parent id is listed in both the parent and children. That way, if the parent has no children, I still have the parent id in my object.
I have been doing some research, and I'm wondering if I should be using
#PrimaryKeyJoinColumn
and/or
#Inheritance(strategy = InheritanceType.JOINED)
I haven't been able to figure out how to implement them though. Any help would be greatly appreciated.
Checkout #JoinColumn.
From Java doc :
Specifies a column for joining an entity association or element collection. If the JoinColumn annotation itself is defaulted, a single join column is assumed and the default values apply.
Example:
#ManyToOne
#JoinColumn(name="ADDR_ID")
public Address getAddress() { return address; }
Example: unidirectional one-to-many association using a foreign key
mapping
// In Customer class
#OneToMany
#JoinColumn(name="CUST_ID") // join column is in table for Order
public Set<Order> getOrders() {return orders;}
With this your entity should look like the following :
#Entity
#Table(name = "parent")
public class Threat {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long parentId;
#Column(name = "name")
private String parentName;
#OneToMany
#JoinColumn(name="parent_id")
private List<Child> children = new ArrayList<>();
}
Now whenever you fetch Parent , you can access the associated child entities.
Additionally you can specify #OneToMany(fetch = FetchType.EAGER) if you always need child entities fetched whenever you query for parent.
Say I have a unidirectional #ManyToOne relationship like the following:
#Entity
public class Parent implements Serializable {
#Id
#GeneratedValue
private long id;
}
#Entity
public class Child implements Serializable {
#Id
#GeneratedValue
private long id;
#ManyToOne
#JoinColumn
private Parent parent;
}
If I have a parent P and children C1...Cn referencing back to P, is there a clean and pretty way in JPA to automatically remove the children C1...Cn when P is removed (i.e. entityManager.remove(P))?
What I'm looking for is a functionality similar to ON DELETE CASCADE in SQL.
If you are using hibernate as your JPA provider you can use the annotation #OnDelete. This annotation will add to the relation the trigger ON DELETE CASCADE, which delegates the deletion of the children to the database.
Example:
public class Parent {
#Id
private long id;
}
public class Child {
#Id
private long id;
#ManyToOne
#OnDelete(action = OnDeleteAction.CASCADE)
private Parent parent;
}
With this solution a unidirectional relationship from the child to the parent is enough to automatically remove all children. This solution does not need any listeners etc. Also a JPQL query like DELETE FROM Parent WHERE id = 1 will remove the children.
Relationships in JPA are always unidirectional, unless you associate the parent with the child in both directions. Cascading REMOVE operations from the parent to the child will require a relation from the parent to the child (not just the opposite).
You'll therefore need to do this:
Either, change the unidirectional #ManyToOne relationship to a bi-directional #ManyToOne, or a unidirectional #OneToMany. You can then cascade REMOVE operations so that EntityManager.remove will remove the parent and the children. You can also specify orphanRemoval as true, to delete any orphaned children when the child entity in the parent collection is set to null, i.e. remove the child when it is not present in any parent's collection.
Or, specify the foreign key constraint in the child table as ON DELETE CASCADE. You'll need to invoke EntityManager.clear() after calling EntityManager.remove(parent) as the persistence context needs to be refreshed - the child entities are not supposed to exist in the persistence context after they've been deleted in the database.
Create a bi-directional relationship, like this:
#Entity
public class Parent implements Serializable {
#Id
#GeneratedValue
private long id;
#OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
private Set<Child> children;
}
I have seen in unidirectional #ManytoOne, delete don't work as expected.
When parent is deleted, ideally child should also be deleted, but only parent is deleted and child is NOT deleted and is left as orphan
Technology used are Spring Boot/Spring Data JPA/Hibernate
Sprint Boot : 2.1.2.RELEASE
Spring Data JPA/Hibernate is used to delete row .eg
parentRepository.delete(parent)
ParentRepository extends standard CRUD repository as shown below
ParentRepository extends CrudRepository<T, ID>
Following are my entity class
#Entity(name = “child”)
public class Child {
#Id
#GeneratedValue
private long id;
#ManyToOne( fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = “parent_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
private Parent parent;
}
#Entity(name = “parent”)
public class Parent {
#Id
#GeneratedValue
private long id;
#Column(nullable = false, length = 50)
private String firstName;
}
Use this way to delete only one side
#ManyToOne(cascade=CascadeType.PERSIST, fetch = FetchType.LAZY)
// #JoinColumn(name = "qid")
#JoinColumn(name = "qid", referencedColumnName = "qid", foreignKey = #ForeignKey(name = "qid"), nullable = false)
// #JsonIgnore
#JsonBackReference
private QueueGroup queueGroup;
#Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
Given annotation worked for me. Can have a try
For Example :-
public class Parent{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="cct_id")
private Integer cct_id;
#OneToMany(cascade=CascadeType.REMOVE, fetch=FetchType.EAGER,mappedBy="clinicalCareTeam", orphanRemoval=true)
#Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private List<Child> childs;
}
public class Child{
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="cct_id")
private Parent parent;
}
You don't need to use bi-directional association instead of your code, you have just to add CascaType.Remove as a property to ManyToOne annotation, then use #OnDelete(action = OnDeleteAction.CASCADE), it's works fine for me.
As in the title, when performing the update operation, the previous child loses the reference to the parent.
Parent side
#OneToMany(cascade =CascadeType.ALL)
#JoinColumn(name = "individual_id")
private List<ContactMedium> contactMedium;
Children side
#Entity
#Table(name = "contactMedium")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class ContactMedium
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id ;
#ManyToOne
private Individual individual;
Patch operation
public Individual patch(Individual individual, Long id) {
Individual objectToSave = individual;
objectToSave.setId(id);
return individualRepository.save(objectToSave);
}
When updating, the previous property loses references to the child. How can I prevent this?
Your mappings seems wrong. Ideally they should be as below:
#Entity
#Table(name = "contactMedium")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class ContactMedium
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id ;
#ManyToOne
#JoinColumn
private Individual individual;
and
#OneToMany(mappedBy = "individual", cascade = CascadeType.ALL)
private List<ContactMedium> contactMedium;
You need to save the ContactMedium and Individual will automatically be saved. Here ContactMedium has the foreign key reference to Individual (and that is what is depicted in your database table screenshot).
Often one use mappedBy as parameter to #OneToMany instead of #JoinColumn to make the relationship two-ways.
Can you please try to change
#OneToMany(cascade =CascadeType.ALL)
#JoinColumn(name = "individual_id")
private List<ContactMedium> contactMedium;
to
#OneToMany(mappedBy = "individual", cascade =CascadeType.ALL)
private List<ContactMedium> contactMedium;
and see if that worked better?
I think you must add the #OneToMany(mappedBy="individual" , cascade =CascadeType.PERSIST) and the #JoinColumn in the #ManyToOne as below:
#OneToMany(mappedBy = "individual", cascade =CascadeType.PERSIST)
private List<ContactMedium> contactMedium;
#ManyToOne
#JoinColumn(name = "individual_id")
private Individual individual;
You should retrieve the entity from the database using the ID first and then update the specific fields and persist the updated entity back.
I have the table that represents kind of Tree node. The mapping below illustrates many-to-many mapping of node.
#Entity
public class Node {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany
#JoinTable(name = "node_dependency",
joinColumns = {#JoinColumn(name = "parent_id")},
inverseJoinColumns = {#JoinColumn(name = "child_id")})
private List<Node> childNodes = new ArrayList<>();
}
It works but I would like to have separate table mapping for the delete query simplicity.
#Entity
public class NodeRelation {
#ManyToOne
private Node parent;
#ManyToOne
private Node child;
}
If I have NodeRelation I can easily find nodes that re-used on different layers of the tree and cannot be safely deletes which is more difficult to do having instead of (One-to-many on Node + Many-to-One on FK in NodeRelation) only Many-to-Many mapping.
I tried different combinations of mapping with composite key that represented by NodeRelation but there is no luck (validation according db schema didn't passed). Please, advice me which mapping is better in this use case.
It is better to not use childNodes association in the Node.
It will be convenient to add id to the NodeRelation.
#Entity
public class Node {
#Id
#GeneratedValue
private Long id;
}
#Entity
public class NodeRelation {
#Id
#GeneratedValue
private Long id;
#ManyToOne
private Node parent;
#ManyToOne
private Node child;
}
Also you can add an unique constraint (parent, child) to NodeRelation (to have the same behavior as #ManyToMany join table has).
It will need to do queries on NodeRelation table only.
I wanted to frame Hibernate OneToMany relationship where
Parent has a composite primary key and Child has a primary key (hibernate-auto generated). Below is my working sample code :
class Parent{
#EmbeddedId
private ParentPk parentPk;
#OneToMany( mappedBy="parent")
private List<ChildType1>;
#OneToMany( mappedBy="parent")
private List<ChildType2>;
#OneToMany( mappedBy="parent")
private List<ChildType3>;
//--setters and getters
}
#Embeddable
public class ParentPk {
private Long parentId;
private BigDecimal version;
//..setters and getters
}
class ChildType1{
#Id
private Long childId;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({ #JoinColumn(name = "parentId"),
#JoinColumn(name = "version") })
private Parent parent;
//..other fields and setters and getters
}
//--ChildType2 and ChildType3 like above
But now I wanted to model above as OneToMany unidirectional relationship, i.e., a child should not reference the parent (want to omit Parent instance in the child class). Is it possible?
An example approach:
#Entity
class Parent {
#EmbeddedId
private ParentPk parentPk;
#OneToMany
#JoinColumns({
#JoinColumn(name = "parentId", referencedColumnName = "parentId"),
#JoinColumn(name = "version", referencedColumnName = "version")
})
private List<ChildType1> children1;
// exactly the same annotations as for children1
private List<ChildType2> children2;
// exactly the same annotations as for children1
private List<ChildType3> children3;
//..other fields and setters and getters
}
#Entity
class ChildType1 {
#Id
private Long childId;
//..other fields and setters and getters
}
//--ChildType2 and ChildType3 like above