Cannot delete detached child from collection in parent in Hibernate - java

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

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:)

How to prevent hibernate from creating a proxy

I have a tricky problem with hibernate using more queries than necessary for a simple findAll call. In my model there is two entities Parent and Child with oneToMany association;
Parent
class Parent{
#id
private long id;
//unique
private String code;
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<OperatorAttribute> children;
}
Child
class Child{
#id
private long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parent_code", referencedColumnName = "code")
#LazyToOne(LazyToOneOption.NO_PROXY) // here i'm trying to tell hibernate to create no proxy and just ignore the field but no luck :/
public Parent parent;
}
The problem is that whenever I try to fetch the list of child using childRepository.findAll() from the database, hibernate make N+1 select query, why ?
I think this may be the explanation for that: IMHO when Hibernate populate the child object, he tries to create a proxy for the parent field,
and for that he needs the id of the parent row, which should normally be the foreign key in the child table, but in my case the #fk isn't binded to the primary key of the Parent table but to a unique column (plz don't ask me why) so in order to populate the id he needs to do an additional select query just to initialize the proxy of the parent field.
So my question is how to prevent Hibernate from creating a proxy for the parent field.
Thanks.
You are right. The proxy needs the #Id of the proxied entity (this way it could be made sure that it could be find). As soon you define the LazyToOneOption.NO_PROXY it tells the system to give back the real object. And this is what happens here. What you get mapped on the result is not a proxy, because with this annotation you explicitly disabled it so you have to get the real object.
Based on the mapping provided you cannot ignore the field because You'll loose the information what was is the Parent on the Child. So with this kind of setup you'll always need to read the parent.
If this field is not needed at all in a specific area, you can create some other mappings to the same table. But be careful! This could introduce a load of other cache related problems.

JPA is not persisting child entities created with static methods

I frequently have to create a record that has child records. I created a utility class U that is not managed by the container with a static method to create the objects. It creates the required entities and relates them to each other and then returns the parent entity - BUT DOES NOT PERSIST.
When I go to persist the parent entity I expect all the attached child entities to be persisted as well but only the parent is persisted.
In another place, quite by accident, I noticed that if I created and attached the entities to the parent in class X that is not directly managed by the container but was created by a class C that was managed by the container - everything works as expected. One other thing to note is that in this case the parent already existed so I set the ID on the child when I created it.
Does this mean I cannot create entities using static methods? Or is there something else going on?
Here are the entities in question.
PARENT:
#Id
#GeneratedValue(generator = "INFO_ID_GEN", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "INFO_ID_GEN", sequenceName = "INFO_ID",allocationSize=1)
#Column(name="INFO_ID")
private int infoId;
#OneToOne(mappedBy="PARENT", cascade=CascadeType.ALL, fetch = FetchType.EAGER)
private CHILD child;
CHILD:
#Id
#Column(name="INFO_ID", insertable=false)
private int infoId;
#OneToOne(cascade={CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name="INFO_ID")
private PARENT parent;
If you need anything else let me know.

Hibernate #OneToOne with updatable = false still updating

I have an hibernate managed entity:
#Entity
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// (omitted useless details)
#OneToOne
#JoinColumn(name = "child_id", updatable = false)
private Child child;
// (omitted useless details)
}
--
#Entity
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// (omitted rest...this is a POJO)
}
Since the responsibility of the update for Child is managed elsewhere, my goal is to simply not update child when the parent is saved. Unfortunately, this updatable = false on the #JoinColumn appears to be getting ignored, saving any changes made to both parent and child.
How can I achieve only saving the parent in a one to one relationship?
Any help is appreciated.
EDIT: Clarification, the Child class is an #Entity as well, but a simple POJO. The relationship between Parent and Child is unidirectional from the parent.
I looked into this for quite a while and looking at the documentation for #JoinColumn annotation and the updatable/insertable properties it says...
"(Optional) Whether the column is included in SQL UPDATE statements generated by the persistence provider."
What this means is setting updatable = false will only prevent the foreign key from being updated (column is included). When you save the parent entity it will also save all child entities attached to the object.
This means that any child properties that are attached to the parent entity when you save will also be persisted. This brings another issue to light if someone else may have updated this child entity, but because you are saving the parent entity with the child entity attached to it, you will un-knowingly overwrite any changes made to the child object.
Solution:
AFAIK the only way to resolve this is to be diligent about the object you save, unless you really need to be saving/updating the child entities don't. Keep your objects self contained, this is the downfalls of lazy/eager loaded properties and saving that same object graph. You could also do like another poster said and set the child entity to null before the save to prevent any updates, but can easily be missed.
If you are OK with saving the entire object tree (parent and children entities) you could add a property that utilizes the #Version attribute to introduce optimistic concurrency. This way if any entity was updated by someone else and you are trying to save an old version it will fail.
#Version
#Column(name=”version”)
private long version;
public long getVersion() { return version; }

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.

Categories