I'm trying to understand jpa relationships.
I have a #OneToMany relationship between two classes.
public class Parent {
#Id
private Long id;
#OneToMany(mappedBy="parent", fetch=FetchType.LAZY)
private List<Child> children;
}
public class Child {
#Id
private Long id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="id")
private Parent parent;
}
I'm would like to get the Parent Id from the list of Child but the Parent is null
List<Child> children = repository.findAll();
Parent parent = children.get(0).getParent(); //for testing, this is null
But when I only get one Child, the Parent is not null
Child child = repository.findOne();
Parent parent = child.getParent() // this is not null
I'm not sure why Parent is null when using findAll();
Related
I have a parent entity-Parent and a child entitiy-Child with one to one relationship.
I am using bidirectional mapping for the entity.
How to save parent without saving the child since child is designed to be a read only column?
Transient error will be reported when persist parent object. org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : test.spring.business.Parent.child
I can't use transient because I need child from database.
#Entity
#Table(name = "parent")
#SequenceGenerator(name = "SEQUENCE_FACTORY", sequenceName = "SEQ_ID", schema = "REQ", allocationSize = 1)
public class Parent implements Serializable {
#Id
#Column(name="id")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQUENCE_FACTORY")
private Long id;
#OneToOne(mappedBy="parent")
public Child child;
// ...
}
#Entity
#Table(name = "child")
public class Child implements Serializable{
#Id
#OneToOne(optional = false,fetch = FetchType.LAZY)
#JoinColumn(name="parent_id",insertable=false,updatable=false)
private Parent parent;
// ...
private Long checkData;
}
#Transactional
public void testParent()
{
Parent p=new Parent();
p.child= new Child();
// ...
//p.child get input...
//...
entityManager.persist(p);
if(p.child.checkData>n)
{
p.child.setParent(p);
entityManager.persist(p.child);
}
}
Since the Child instance is new/transient you encounter this error. It indicates that hibernate does not know which child the parent is associated to in DB.
Since the child is read only, change the test to
#Transactional
public void testParent()
{
Parent p=new Parent();
p.child= entityManager.find(Child.class, 100L);
entityManager.persist(p);
}
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();
}
I use Spring Data Jpa and Hibernate is the provider.
I have a Parent class mapped as follows:
#Entity
#Table(name="parent")
public class Parent {
private List<Child> childs;
private List<AnotherChild> anotherChilds;
#OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
public List<Child> getChilds() {
return childs;
}
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
public List<AnotherChild> getAntoherChilds() {
return anotherChilds;
}
}
and child:
#Entity
#Table(name="child")
public class Child {
private Parent parent;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "column_name")
public Parent getParent() {
return patern;
}
}
#Entity
#Table(name="another_child")
public class AnotherChild {
private Parent parent;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "column_name")
public Parent getParent() {
return patern;
}
}
When I load the parent from the database, it doesn't load the list of
child immediately and
When I call parent.getChilds(), it returns
null.
Can you give some advice? Am I wrong anywhere? Thanks.
EDIT:
After some research, I realize that when I have only single child, it loaded eagerly (like it should). But when I have multiple child, it doesn't - even though it has been marked FetchType.EAGER and the other FetchType.LAZY.
Note: If I marked both as FetchType.EAGER, it'll throws MultipleBagFetchException: cannot simultaneously fetch multiple bags.
The same happened when I annotate it using #Fetch(FetchMode.JOIN)
If added Entity annotation parent.getChilds() should not come empty.it would be better as you do Entity.
#Entity
#Table(name="PARENT_TBL")
public class Parent {
//other fields
#OneToMany(mappedBy = "parent",fetch = FetchType.LAZY,cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE},orphanRemoval = true)
private List<Child> childs;
//getter setter
}
#Entity
#Table(name="CHILD_TBL")
public class Child {
//other fields
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PARENT_ID")
private Parent parent;
//getter setter
}
Example Get Parent Query;
public Parent getParent(long parentId) throws Exception {
session = sessionFactory.openSession();
Criteria cr = session.createCriteria(Parent.class, "parent");
cr.setFetchMode('parent.childs', FetchMode.JOIN);
cr.add( Restrictions.eq("parent.id", parentId));
Parent parent = cr.uniqueResult();
tx = session.getTransaction();
session.beginTransaction();
tx.commit();
return parent;
EAGER loading of collections means that they are fetched fully at the time their parent is fetched. So if you have Parent and it has List, all the childs are fetched from the database at the time the Parent is fetched.
LAZY on the other hand means that the contents of the List are fetched only when you try to access them. For example, by calling parent.getChilds().iterator(). Calling any access method on the List will initiate a call to the database to retrieve the elements. This is implemented by creating a Proxy around the List (or Set). So for your lazy collections, the concrete types are not ArrayList and HashSet.
Standard way to define one-to-many relationship in Hibernate/JPA is to have a reference in a Child object to its Parent object.
#Entity
#Table(name="PARENT")
public class Parent {
// ...
#OneToMany(mappedBy="department")
private Set<Child> children;
// ...
}
#Entity
#Table(name="CHILD")
public class Child {
// ...
#ManyToOne
#JoinColumn(name="parent_id")
private Parent parent;
// ...
}
The problem with this method is that Child becomes a heavyweight class, which is harder to send across the wire, etc.
Is it possible to define a one-to-many relationship with no Parent object referenced from Child and with no additional reference/join table? In that case Child class defined as follows:
#Entity
#Table(name="CHILD")
public class Child {
// ...
#Column(name="DEPARTMENT_ID")
private Long departmentId;
// ...
}
If you are using JPA 2.0, it is possible OneToMany uni-direction with no parent entity at child entity.
Parent.java
#Entity
#Table(name="PARENT")
public class Parent {
#OneToMany
#JoinColumn(name = "PARENT_ID", referencedColumnName = "ID")
private Set<Child> children;
}
Child.java
#Entity
#Table(name="CHILD")
public class Child {
// No need to hold parent entity
//#ManyToOne
//#JoinColumn(name="parent_id")
//private Parent parent;
}
More Reference
#Entity
public class Parent {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
int id;
#OneToMany(cascade=CascadeType.REMOVE)
List<Item> children = new ArrayList<Child>();
}
#Entity
public class Child {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
int id;
}
As you can see above, I have a OneToMany-Relation between parent and child. If I delete an instance of parent, all children are also deleted. Is there a way to get this working the other way round as well?
Parent p = new Parent();
Child c = new Child();
p.children.add(c);
EntityManager.persist(p);
EntityManager.persist(c);
EntityManager.remove (c);
This code runs without exception, but when I load p the next time, there is a new child attached.
If you want deletes to work from both sides, you need to define a bi-directional relationship between Parent and Child:
// in Parent
#OneToMany(cascade=CascadeType.REMOVE, mappedBy="parent")
List<Item> children = new ArrayList<Child>();
// in Child
#ManyToOne
Parent parent;