Skip child to fetching of parent - JPA - java

I am facing an issue where the data is getting fechted recursively. I wanted to avoid the child to fetch the parent data. Which is causing a recursive issue.
I have mentioned the code below
Pojo Structure
class Parent {
..
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Child> childs;
..
}
class Child {
..
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parentId")
private Parent parent;
..
}
Fetching the data like this
` em = EMF.get().createEntityManager();
Query q = em.createQuery("Select p from Parent p", Parent.class);
List<Parent> parents = q.getResultList();
// Till this point all looks good but when the code gets executed
parent.getChilds();
`
It is fetching the data like this:
Parent
child1
Parent
child2
Parent
child2
Parent
..
..
child2
..
Which I dont need I just want the data like this:
Parent1
child1
child2
Parent2
child1
child2
child3

While FetchType.EAGER is a contract, FetchType.LAZY is only a hint, because lazy fetching is not always possible. This may depend e.g. on the JPA provider you use as well as on its configuration. Lazy fetching is particularly problematic with to-one relationships.
If every Child has a Parent, try adding optional=false to your #ManyToOne. This might enable lazy fetching.
Since the Parent entity is already loaded into the persistence context, populating Children.parent shouldn't trigger queries against the database. Are you actually seeing queries being executed? How do you know Children.parent is being loaded? If you are accessing the value to check that fact, chances are you are actually triggering the on-demand loading yourself.

It'll work as infinite loop for hefty data. Best practice is to mention #JsonIgnore at child class column.
Thank me Later

To avoid this problem of cyclic references, I used a Mapper with MapStruct (see official documentation for a quick setup) :
Then I can easily write a mapper to ignore a property like this :
public interface SecondaryObjectMapper {
#Mapping(target = "primaryObject.secondaries", ignore=true),
SecondaryObjectDto toSecondaryObjectDto(SecondaryObject source);
}
and use it like this for example :
repository.findAll(pageable).map(secondaryObjectMapper::toSecondaryObjectDto)

To Avoid this issue , Please declare below annotation Parent & Child getter methods
#JsonBackReference
public Parent getParent() {
return parent;
}
#JsonManagedReference
public List<Child> getChilds() {
return childs;
}

Related

Fetching a list of parent entities with a filtered collection of children in Spring Data JPA

So I've been stuck on this problem for about half a day so I am wondering if I am just over-complicating things.
My application has three different Java object classes: Grandparent, Parent, and Child. Each Grandparent contains a List of Parents, and each Parent contains a List of Children. Child has an "isWellBehaved" property, which is a boolean.
We are using Spring Data JPA and Hibernate in order to map the data to a database. Our application contains a lot of nested entities and circular relationships and we are relying on projections to keep our request size down.
The Problem: given a grandparent id, I want to return a list of all Parents (as projections). I want each of the Parents to contain a list of Child projections, but only if the Child is well behaved. The rest of the children in the collection should be filtered out from the collection.
What would be the simplest way to achieve this? We are not using Hibernate filters at the moment and I am not keen on introducing them as we are not likely to need them anywhere else (either way, would it be suited for this purpose?). I have used JPA Criteria API predicates (very little) but find it difficult to adapt that to this particular scenario. Is a native query the way to go? I've started going in that direction but am having some issues mapping all the fields to our Spring entity due to all the nested dependencies so just want to make sure I am even headed in the right direction before I continue.
My (simplified) parent entity class looks like this:
#Entity
#Table(name="parent"
public class Parent {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="parent_id")
Integer id;
Integer grandparentId;
#OneToMany(mappedBy = "parent")
List<Child> children;
}
Child class:
#Entity
#Table(name="child"
public class Child {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="child_id")
Integer id;
#ManyToOne
#JoinColumn(name="parent_id")
Parent parent;
boolean isWellBehaved;
}
Parent repository interface:
#RepositoryRestResource(excerptProjection = ParentProjection.class)
public interface ParentRepository extends JpaProjectionRepository<Parent, Integer, ParentProjection> {
List<ParentProjection> findAllByGrandparent_Id(Integer grandpaId);
}
You can use #Where annotation of hibernate on collection. It will be something like
#Entity
#Table(name="parent"
public class Parent {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="parent_id")
Integer id;
Integer grandparentId;
#Where(clause = "isWellBehaved=true")
#OneToMany(mappedBy = "parent")
List<Children> children;
}
As you have said:
I want each of the Parents to contain a list of Child projections, but only if the Child is well behaved.
List<childerns>allChilderns=parentsList.stream().map(parent>dao.findchildernByParentId()).collect(Collectors.List());
allChilderns.stream().filter(childern->childern.isWellBehaved()==true).collect(Collectors.toList());
Get all the parents by GrandParentId--the one which you are doing.
Once you got all the parents,for each parent findchildernByParentId.
and then filter out the childern on the basis of condition.
Let me know:)

Lazy loading with CrudRepository

I have a simple parent-child relation (one to many). And I am retrieving parents in two endpoints. One to get a list of parents and one to get a single parent. On the list, I don't want to serialize a list of children for each parent. I want to show a list of children only when I am getting a single parent.
I am working with spring boot and CrudRepository.
I tried
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
also fetch = FetchType.LAZY and in the end, I was writing custom HQL with FETCH keyword.
Parent Model
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#JoinColumn(name = "parent_id")
private List<Child> children;
Child Model
#Column(name = "parent_id")
#JsonIgnore
private Long parentId;
Parent Repository
public interface ParentRepository extends CrudRepository<Parent, Long>
Parent Service
List<Parent> findAll() {
return StreamSupport
.stream(repository.findAll().spliterator(), false)
.collect(Collectors.toList());
}
As I said I want to sometimes serialize a list of children in this relation and in some cases not.
You may be able to do this using JsonView or JsonFilter with Jackson. Another option would be to separate the concerns, i.e. use a DTO to control the serialized view of the entity.
Here is a link to a tutorial on some of these Jackson features: https://www.baeldung.com/jackson-serialize-field-custom-criteria
Most likely it’s due to the default Open Session in View. Starting with version 2.0
If you added below line in your application.properties configuration file, then it should work
spring.jpa.open-in-view=false
Ok, I finally have done it. I wrote a dedicated HQL for Parent without children.
#Query("SELECT new Parent(a.parentId, a.name, a.address, a.city) FROM Parent a WHERE a.otherId= :id")
List<Parent> findAllBySomeOtherIdWithoutChildren(#Param("id") Long id);
It looks like this is the fastest way for it. Thanks for all suggestions.

Cannot delete detached child from collection in parent in Hibernate

I have the following entities with a parent-child relationship:
public class Parent {
#Id #GeneratedValue String id;
#Version Long version;
#OneToMany(mappedBy = "parent", orphanRemoval = true)
#Cascade({CascadeType.ALL})
Set<Child> children;
// getters and setters
}
public class Child {
#Id #GeneratedValue String id;
#ManyToOne
#JoinColumn("parent_id")
Parent parent;
// getters and setters
}
I retrieve a Parent for edit on the web UI by copy properties to a ParentDto, which has a list of ChildDtos.
Once I'm done editing, I send the ParentDto object back and copy all properties into a new Parent object (parent) with a new HashSet to store the Children created from the list of ChildDtos.
Then I call getCurrentSession().update(parent);
The problem
I can add children, update children, but I can't delete children. What is the issue here and how do I resolve it?
Thanks in advance.
You have a bidirectional association, you need to remove from Child class the link to the parent class, try to make Parent reference to null, and also set the Set<Child> to a new HashSet<Child> or whatever your implementation is.
Then save the changes that will remove the children form the table.
This action can only be used in the context of an active transaction.
public void remove(Object entity);
Transitions managed instances to removed. The instances will be deleted from the datastore on the next flush or commit. Accessing a removed entity has undefined results.
For a given entity A, the remove method behaves as follows:
If A is a new entity, it is ignored. However, the remove operation cascades as defined below.
If A is an existing managed entity, it becomes removed.
If A is a removed entity, it is ignored.
If A is a detached entity, an IllegalArgumentException is thrown.
The remove operation recurses on all relation fields of A whose cascades include CascadeType.REMOVE. Read more about entity lifecycle

JPA + Hibernate - How to get FK of child entity without fetching that entity?

A possible answer to my question is located here:
How can I retrieve the foreign key from a JPA ManyToOne mapping without hitting the target table?
However, the preferable solution (property access) does not work in my case (I got missing column exception - why?)
The model looks like this: Entities Parent and Child. Table parent has column child_id which is PK of child table so it is typical #ManyToOne relation.
Now the point is, if I fetch Parent entities, I need to have access to FK value (aka. PK of Child entity) without fetching Child entities. How can I do that?
I use Annotations and my mapping looks as follows:
#Entity
#Table(name = "parent")
public class Parent extends AbstractEntity {
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "patent_id", nullable = true)
private Child child;
#Column(name="child_id",insertable=false,updatable=false)
private Integer childId;
public Child getChild() {
return patent;
}
public void setChild(Child child) {
this.child = child;
}
public Integer getChildId(){
return childId;
}
}
And what I want to do is call parent.getChild().getId() without extra fetches of Child entity from DB.
According to the answer I have mentioned above, If I moved annotations from field to getter (in Parent entity am I right?), requested behavior would be out of the box. However, when I move annotations to getter, I get a validation exception that child column is missing (curious, why child not child_id as declared?)
PS: Shown workaround to declare a FK column as separate field works fine, but I don't think that this is the way it should be done.
OK, after reading following article http://256stuff.com/gray/docs/misc/hibernate_lazy_field_access_annotations.shtml
I have realized, that property access should be to the property I want to fetch, not the actual child object. So changing id access of AbstractEntityfrom field to property, makes the trick.

Retrieving a child object after a commit on an entity object

Lets say I retrieve an entity object that looks like this:
#Entity
public class Mother {
...
#OneToMany(mappedBy = "mother",
targetEntity = Child.class,
fetch = FetchType.LAZY)
public List<Child> getChildren() {
return children;
}
}
When retrieving the above object, I commit the transaction (and close the session associated with the object). Later on in the code, there is a need to retrieve the children. If I wanted to keep the fetch type as LAZY, is there a way to use the Mother object and still be able to call getChildren() to retrieve the children? Or would I have to just bite the bullet and query the children via the key of the Mother?
If I wanted to keep the fetch type as LAZY, is there a way to use the Mother object and still be able to call getChildren() to retrieve the children?
Not if the EntityManager has been closed.
Or would I have to just bite the bullet and query the children via the key of the Mother?
You could retrieve the children when getting the mother using a FETCH JOIN:
SELECT m
FROM Mother m LEFT JOIN FETCH m.children
WHERE m.id = :id
Other options include:
using the Open Entity Manager in View pattern (if you are using a webapp)
using an extended persistence context.

Categories