I have a bi-directional #OneToMany self-join on a JPA 2.0 entity and I find that I have to persist both sides of the relationship for the changes to be reflected in the persistence context. In this situation I am merging the parent and persisting the child.
I manually maintain both sides of the relationship by adding to the child collection when setting the parent. I thought that this would be enough and that I would not have to persist both sides.
Is this behaviour correct, or am I doing something wrong? I have tried setting various combinations of cascade options on both sides of the relationship to no avail.
#Entity
public class Context extends AbstractEntity implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
#ManyToOne
private Context parent;
#OneToMany(mappedBy = "parent")
private List<Context> children;
#OneToMany
private List<Task> tasks;
private void addChild(Context child) {
this.children.add(child);
}
public void setParent(Context parent) {
this.parent = parent;
this.parent.addChild(this);
}
//Getters and setters
}
//#ManagedBean making data changes
public void createContext() {
context.setParent((Context) selectedNode.getData());
contextFacade.edit(context.getParent());
contextFacade.create(context);
//Display result
}
Related
I want to select parent with child that i want.
But when I select my parent I have to show all the childs
How can i do that?
Example:
public class parent{
private Integer id;
#OnetoMany
#JoinColumn(name="parentId")
private List<child> children;
}
public class child{
private Integer id;
private Integer parentId;
}
findByIdAndchildType(Integer id, String type)
I want to see : parent(id) - > child (type)
But i can see parent(id) - > child(othertype), child(othertype1), child(type)
It sounds to me that you're trying to get a bi-directional relation. This is possible by adding the mapping to both sides of the relation.
For example, add a #ManyToOne mapping to the Child entity. Be aware that you should probably remove your parentId field since now you can access it by using child.getParent().getId().
#Entity
public class Child {
#Id
private Integer id;
#ManyToOne
#JoinColumn(name = "parentId")
private Parent parent;
// Remove parentId field
// Getters + Setters ...
}
NOTE: If you want to keep the parentId field, you'll have to choose which two of the mappings (getParentId() or getParent().getId()) you want to use for inserting and updating entities. The other field should have both insertable = false and updatable = false.
The next step is to change the #OneToMany mapping to use mappedBy:
#Entity
public class Parent {
#Id
private Integer id;
#OneToMany(mappedBy = "parent") // Change this
private List<Child> children;
// Getters + Setters ...
}
If you want to retrieve a specific child with its parent, you can now create a repository for Child entities:
public interface ChildRepository extends JpaRepository<Child, Integer> {
}
After that, you can get a specific child by using:
Optional<Child> child = repository.findById(123); // 123 is the ID of the child in this case
Optional<Parent> parent = child.map(Child::getParent);
With Spring boot 1.x that would be:
Child child = repository.findOne(123);
Parent parent = null;
if (child != null) {
parent = child.getParent();
}
In a One-To-Many relationship, how can I delete a child element without having to find and load up the parent, removing the element, update parent, THEN delete the child? To further illustrate my problem, I have the two classes Foo (parent) and Don (child of Don):
#Entity
public class Foo {
#Id
#GeneratedValue
private int id;
#OneToMany
private List<Don> dons;
public int getId() {
return id;
}
public List<Don> getDons() {
// (loads dons as because lazy loading)
return dons;
}
}
#Entity
public class Don {
#Id
#GeneratedValue
private int id;
public int getId() {
return id;
}
}
If I have a Don instance with several Foos referring to it, I would get the following exception:
Cannot delete or update a parent row: a foreign key constraint fails
I know I can remove the instance from Foo, but is there a way to remove Don instances without finding Foos? (as of performance)
I think your situation should be: delete a Foos instance with several Dons referring to it
You can add cascade attribute, then when you delete a Foos instance, the associated Dons instances would be deleted automatically without giving foreignkey error:
#OneToMany(cascade = {CascadeType.ALL})
private List<Don> dons;
As stated in this post, a bidirectional binding is required in order to delete the object. Adding a reference from Don to Foo annotated with #ManyToOne, and added mappedBy="parent" to Foo.dons solved my issue. The final code:
#Entity
public class Foo {
#Id
#GeneratedValue
private int id;
// Added mapped by, which refers to Don.parent
#OneToMany(mappedBy = "parent")
private List<Don> dons;
public int getId() {
return id;
}
public List<Don> getDons() {
// (loads dons as because lazy loading)
return dons;
}
}
#Entity
public class Don {
#Id
#GeneratedValue
private int id;
// Added parent
#ManyToOne
private Foo parent;
public int getId() {
return id;
}
// Remember to set parent, otherwise we will loose the reference in the database.
public void setParent(Foo parent) {
this.parent = parent;
}
}
I'm trying to find a way to manage in a lightweight fashion two models that have a OneToMany relationship but will never be persisted.
My search has lead me to the javax.persistence that seems to be able to do what i want but i do not seem to be able to make it work.
As tests always say much more than a speech, here's what i'd like to achieve:
public void test_relationship() {
Parent p = new Parent("Mary");
Child c1 = new Child("Hugo");
Child c2 = new Child("Charly");
Child c3 = new Child("Françine");
p.addChild(c1)
Assert.assertEquals(p, c1.getParent());
p.removeChild(c1)
Assert.assertNull(c1.getParent());
p.addChildren(c1, c2)
Assert.assertEquals(p, c1.getParent());
Assert.assertEquals(p, c2.getParent());
c1.removeParent();
Assert.assertFalse(p.hasChild(c1));
c1.setParent(p);
Assert.assertTrue(p.hasChild(c1));
}
All this without a database. It's only purpose is to facilitate the access from one object to another. These objects will be built depending on data received as an HTTP request payload (JSON format) and will need to be serialized back to JSON as part of the response.
For now here's what i've done
#Entity
public class Parent implements Serializable {
private Collection<Child> children = new HashSet<Child>();
#Id
private String id;
#OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
public Collection<Child> getChildren() {
return children;
}
public void addChild(child) {
this.children.add(child);
}
public void removeChild(child) {
this.children.remove(child);
}
public boolean hasChild(child) {
this.children.contains(child);
}
}
#Entity
public class Child implements Serializable {
private Parent parent;
#Id
private String id;
#ManyToOne
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
public void removeParent() {
this.parent = null;
}
}
Edit:
I'm expecting the relationship behavior to come from javax.persistence. Maybe through an EntityManager ? I'm really confused on how those work. I know I could code this behavior myself but I would like to avoid to do this on each relation of each of my entities and have the driest code possible.
You are part of the way there. The bit that is missing is that when you create/update/remove one side of a Parent <-> Child relationship you need to do the same on the other side.
So for example
public void setParent(Parent parent) {
if (this.parent != null) {
this.parent.removeChild(this);
}
this.parent = parent;
parent.addChild(this);
}
(And change childs to children or the grammar monster will eat you!)
I am new to JPA and am having some difficulty understanding the "Direction in Entity Relationships" concepts as described here:
http://docs.oracle.com/javaee/7/tutorial/doc/persistence-intro001.htm#BNBQI
Is uni- or bidirectionality something that you choose when designing your entities or is it given by the database schema? Like in the order application (http://docs.oracle.com/javaee/7/tutorial/doc/persistence-basicexamples001.htm), could you for example design it so that the lineitem knows about which orders it belongs to, but an order wouldn't know which lineitems it has?
You decide whether a relationship is uni-directional or bi-directional by the fields and annotations you include on the entities.
Uni-directional
#Entity
public class Parent(){
#OneToMany
private List<Child> children;
}
#Entity
public class Child(){
}
Bi-directional
#Entity
public class Parent(){
#OneToMany
private List<Child> children;
}
#Entity
public class Child(){
#ManyToOne
#JoinColumn
private Parent parent;
}
As you can see the uni-directional relationship does not allow the child to access the parent, while the bi-directional does allow parent access. This link is created by adding an annotated field to the child of the parent's type and is completely optional. It boils down to a design decision.
Of course the database must support the relationship, meaning the proper primary/foreign keys are established to link the tables, but nothing special is required in your database.
One important concept to be aware of when modeling these relationships is the owning entity. I have written this article about the topic which may be helpful.
That depend upon your requirement
Unidirectional
#Entity
#AutoProperty
public class OneToOneUnidirectionalA implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#OneToOne
private OneToOneUnidirectionalB b;
private String s;
// Setters, Getters, Constructors, Pojomatic...
}
#Entity
#AutoProperty
public class OneToOneUnidirectionalB implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
// No reference to OneToOneUnidirectionalA
// since this is a unidirectional relationship
private String s;
// Setters, Getters, Constructors, Pojomatic...
}
Bidirectional
A owns the relationship. We need to avoid Pojomatic circular reference issues too:
#Entity
#AutoProperty
public class OneToOneBidirectionalA implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Property(policy=PojomaticPolicy.NONE)
#OneToOne
private OneToOneBidirectionalB b;
// Setters, Getters, Constructors, Pojomatic...
}
#Entity
#AutoProperty
public class OneToOneBidirectionalB implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Property(policy=PojomaticPolicy.NONE)
#OneToOne(mappedBy="b")
private OneToOneBidirectionalA a;
// Setters, Getters, Constructors, Pojomatic...
}
I'm annotating my domain model for a shop (with JPA 2, using a Hibernate Provider).
In the shop every product can have a Category. Each category can be assigned to several super- and subcategories, meaning a category "candles" can have "restaurant" and "decoration" as parents and "plain candles" and "multi-wick candles" as children, etc.
Now I want to avoid cyclic references, i. e. a category "a" that has "b" as its parent which in turn has "a" as its parent.
Is there a way to check for cyclic references with a constraint in JPA? Or do I have to write some checks myself, maybe in a #PostPersist-annotated method?
Here's my Category class:
#Entity
public class Category {
#Id
#GeneratedValue
private Long id;
private String name;
#ManyToMany
private Set<Category> superCategories;
#ManyToMany(mappedBy="superCategories")
private Set<Category> subCategories;
public Category() {
}
// And so on ..
}
I believe you would have to check this through a business rule in your code. Why don't you separate these ManyToMany mappings in a separate Entity ? Like for example:
#Entity
#Table(name = "TB_PRODUCT_CATEGORY_ROLLUP")
public class ProductCategoryRollup {
private ProductCategory parent;
private ProductCategory child;
#Id
#GeneratedValue
public Integer getId() {
return super.getId();
}
#Override
public void setId(Integer id) {
super.setId(id);
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="ID_PRODUCT_CATEGORY_PARENT", nullable=false)
public ProductCategory getParent() {
return parent;
}
public void setParent(ProductCategory parent) {
this.parent = parent;
}
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="ID_PRODUCT_CATEGORY_CHILD", nullable=false)
public ProductCategory getChild() {
return child;
}
public void setChild(ProductCategory child) {
this.child = child;
}
}
In this way, you could before Saving a new entity, query for any existing Parent-Child combination.
I know I come back to the problem after several years but, I faced this problem, followed all of your resolutions and it didn't work for me. But I found the best solution using #JsonIgnoreProperties which solved the problem perfectly. In fact, I injected #JsonIgnoreProperties into the entity classes linked by a mapping like here:https://hellokoding.com/handling-circular-reference-of-jpa-hibernate-bidirectional-entity-relationships-with-jackson-jsonignoreproperties/