collection was not processed by flush() exception In JPA - jpa

I have the Entities as follows;
Claimant:
#OneToMany(mappedBy = "payTo", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#NotAudited
private Set<Payment> payments = new HashSet<Payment>();
Payment:
#OneToMany(mappedBy = "rofOf", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
private Set<Payment> returnOfFundings = new HashSet<Payment>();
When doing claimant.merge()
getting the following exception "collection [com.bfds.saec.domain.Payment.returnOfFundings] was not processed by flush()"
for the above one solution i found that just reload the Claimant with joining with Payment before merge.
But Please let me know,Is there any other way is there to solve the above problem as i don't want to reload the Claimant with payment.
What may be the root-cause for the problem ?? Is there any problem the relation I have defined there??

Root cause of problem seems to be HHH-273 bug in Hibernate. According comments it also pops up when Envers touches collection. Because it is fixed in version 4.0.1, best way to get rid of it is to update Hibernate.

Related

Spring JPA Entities: related problems of Ignite error, LAZY fetching, and too-m, minimizing database use and working with Ignite

I'm writing some entity relationships using Spring Data and Java. I have this pair of classes (edited):
Subject:
#Entity
#Table(name = "SUBJECT")
// Lombok, etc., attributes removed
public class Subject {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "ID", updatable = false, nullable = false)
#JsonProperty("id")
private Long id;
#OneToMany(targetEntity = SubjectResource.class, mappedBy = "subject", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<SubjectResource> resources;
}
SubjectResource:
#Entity
#Table(name = "SUBJECT_RESOURCE")
// Lombok, etc., attributes removed
public class SubjectResource {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "ID", updatable = false, nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SUBJECT_ID")
private Subject subject;
}
I'm trying to solve these issues:
Question 1: Can I manipulate #OneToMany or #ManyToOne to NOT have the child class recurse its parent?
Fetch of resources returns subject data:
/subject/101:
{"id":101,"resources":[{"id":1001,"subject":101},{"id":1002,"subject":101},{"id":1003,"subject":101},{"id":1004,"subject":101}]}
/subjectResource/1001:
{id:1001,subject:{"id":101,"resources":[{"id":1001,"subject":101},{"id":1002,"subject":101},{"id":1003,"subject":101},{"id":1004,"subject":101}]}}
That is, /subjectResource/1001 returns its ID and the entire /subject/101 query.
How can I have just the subjectResource data, without its parent?
Question 2: Through #OneToMany or #ManyToOne can I get Hibernate to fetch on a "1" (O(1)) basis?
When /subjects does its thing, it works with Hibernate on a "n+1" (O(n)) basis: 1 fetch of subjects, n fetches of resources, one for each subject ID.
I could force a single fetch through a fancy repository #Query annotation ("select s from subject s left join fetch s.resources"). But that means putting the subject : subject_resource definitions in two places, etc.
Can JPA implementation / Hibernate be forced to do a join, and thus make only one database call, through annotation within an entity class?
Question 3: How do I get my Spring Data / Spring Repository to cooperate with Ignite, and have the cache return the data it already had on the first call?
I'm usng FetchType.LAZY, as all good pupils do. I'm also storing things in Apache Ignite. For /subject/101 the initial call fetches everything OK, returning it in JSON. But the second call gets from the Ignite cache, which complains about being out of transaction.
How do get my LAZY fetches to cooperate with Ignite?
Thanks,
Jerome.

Can't store OneToMany relationsship in my Database

I have a problem with the relationsship #OneToMany in JPA. I want to save a relationsship between a Customer and a Message Object but i got a NullPointerException. I don't know why, because i thought that the follwoing code will work smoothly.
Here's what i trie to do:
Customer new = new Customer();
new.setEmail(email);
new.setUserId(userId);
new.setLastname(lastname);
new.setFirstname(firstname);
new.setPhone(phone);
quick.customerNew(new);
Messages msg = new Messages ();
msg.setMessage(message);
quick.newMessage(msg);
//Here i got the NullPointerException
new.getCustomerMessages.add(msg);
quick.customerUpdate(new);
The Customer Object and the Message Object are stored in the DB. But the relationsship dosen't exists and i got, as i said, the NullPointerException
public class Customer implements Serializable {
[...]
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "_id_info", referencedColumnName = "_id")
private Set<Messages> customerMessages;
[getter/setter]
}
//Here i got the NullPointerException
new.getCustomerMessages.add(msg);
If this line throws the NullPointerException, it can mean two things: either "new" (geez, it hurts just to type it as a variable name) is null, or getCustomerMessages() returns null.
Since your code reaches this point, by accessing "new" multiple times before, I assume that "new" isn't the culprit here.
Since you never call setCustomerMessages() in your code, and there are no signs that any other calls would set your customerMessages attribute, I assume that this will be member you need to set.

StackOverflowError when persisting entities with bidirectional relation

I have two kinds of entities with a bidirectional ManyToMany relation between them. I don't want to post their structure here, because I don't think it would help. Any changes in that relation didn't help, however the relation ist annotated as follows
// relation in the first entity class
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "Entity1_Entity2",
joinColumns = { #JoinColumn(name = "entity1") },
inverseJoinColumns = { #JoinColumn(name = "entity2") })
private List<Entity2> subEntities = new ArrayList<>();
// relation in the second entity class
#ManyToMany(mappedBy = "relatedEntities", fetch = FetchType.LAZY)
private List<Entity1> owningEntities = new ArrayList<>();
So there are possibly circular dependencies. But as far as I know EclipseLink as well as most other JPA implementations can manage this. However while the persisting of few related entities works wothout problems, I get a StackOverflowError when there are too much of them:
Exception in thread "main" java.lang.StackOverflowError
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.extractPrimaryKeyFromObject(ObjectBuilder.java:3011)
at org.eclipse.persistence.internal.sessions.AbstractSession.getCacheKeyFromTargetSessionForMerge(AbstractSession.java:2702)
at org.eclipse.persistence.internal.sessions.MergeManager.getTargetVersionOfSourceObject(MergeManager.java:196)
at org.eclipse.persistence.internal.queries.ContainerPolicy.createWrappedObjectFromExistingWrappedObject(ContainerPolicy.java:728)
at org.eclipse.persistence.mappings.CollectionMapping.mergeIntoObject(CollectionMapping.java:1648)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeIntoObject(ObjectBuilder.java:4132)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeChangesIntoObject(ObjectBuilder.java:4065)
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:839)
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:698)
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChanges(MergeManager.java:309)
at org.eclipse.persistence.mappings.CollectionMapping.mergeIntoObject(CollectionMapping.java:1638)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeIntoObject(ObjectBuilder.java:4132)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeChangesIntoObject(ObjectBuilder.java:4065)
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:839)
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:698)
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChanges(MergeManager.java:309)
at org.eclipse.persistence.mappings.CollectionMapping.mergeIntoObject(CollectionMapping.java:1638)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeIntoObject(ObjectBuilder.java:4132)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.mergeChangesIntoObject(ObjectBuilder.java:4065)
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:839)
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChangesOfWorkingCopyIntoOriginal(MergeManager.java:698)
at org.eclipse.persistence.internal.sessions.MergeManager.mergeChanges(MergeManager.java:309)
at org.eclipse.persistence.mappings.CollectionMapping.mergeIntoObject(CollectionMapping.java:1638)
...
I already removed cascaded persisting as you can see in the annotations above as I could imagine that this caused the depth of recursion. But again I got this error. When I increase the allowed stack it works again, but in my opinion the problem isn't solved then. But it tells me that the recursion isn't endless. Also the error only occurs because of the bidirectional relation because is isn't thrown when i make it unidirectional.
So the questions are: Why is the recursion depth increased when more entities are persisted? And how can this be avoided without making the relation unidirectional?

cascading on a target entity with other relationships

I have a manytomany relation mapped with these 3 entities :
#Entity
public class ApplicatifDo {
.....
#OneToMany(cascade = CascadeType.ALL, mappedBy = "applicatifDo", fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ApplicatifTerminalDo> applicatifTerminalSet;
.....
}
#Entity
public class ApplicatifTerminalDo {
......
#ManyToOne
#JoinColumn(name = "idApplicatif", nullable = false)
private ApplicatifDo applicatifDo;
#ManyToOne
#JoinColumn(name = "idTerminal", nullable = false)
private TerminalDo terminalDo;
#Column
private String remarques;
......
}
#Entity
public class TerminalDo {
......
#OneToMany(cascade = CascadeType.ALL, mappedBy = "terminalDo", fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ApplicatifTerminalDo> applicatifTerminalSet;
......
}
I try to do many cascading tests on the join table ApplicatifTerminalDo from the two entities ApplicatifDo and TerminalDo. When I create or update a ApplicatifTerminalDo in the Set the cascading works well, but when it comes to orphanRemoval or delete It's not working
First :
For the delete I get the error :
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`softtwo`.`applicatifterminal`, CONSTRAINT `FK_295tcnx7wjuvv5se1g3vldxxn` FOREIGN KEY (`idApplicatif`) REFERENCES `applicatif` (`id`))
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
at com.mysql.jdbc.Util.getInstance(Util.java:384)
.....
I would like that when I delete an entity ApplicatifDo or TerminalDo all rows related to them in the ApplicatifTerminal join table get deleted as well.
Second :
For the orphanRemoval, when I delete an element from the Set of ApplicatifTerminalSet in my ApplicatifDo entity and do a merge, then to test it I do a find by his Id of parent entity to get a new exact same entity and count the number of elements in the Set I get the good number (the number at the biginning with one less). But in my database I still have all my datas of my Set.
The code :
//My applicatifDo1 has 4 elements in the ApplicatifTerminalSet here
Assert.assertEquals(applicatifDo1.getApplicatifTerminalSet().size(), 4);
Iterator<ApplicatifTerminalDo> iterator = applicatifDo1
.getApplicatifTerminalSet().iterator();
boolean first = true;
while (iterator.hasNext()) {
ApplicatifTerminalDo element = iterator.next();
if (!first) {
element.setRemarques("remarques updated");
} else {
iterator.remove();
first = false;
}
}
// updateApplicatifDo do just a merge
applicatifDao.updateApplicatifDo(applicatifDo1.getId(), applicatifDo1);
ApplicatifDo applicatifDo = applicatifDao
.findApplicatifDo(applicatifDo1.getId());
Assert.assertEquals(applicatifDo.getApplicatifTerminalSet().size(), 3);
When I do that the update of setRemarques() works well. I have no error in the console when I do that. Then the remove seems to work because I retrieve the same object by his Id it still says I have 3 elements, then the fourth has been deleted : BUT, when I look in phpmyadmin my 4 elements/relations in my appplicationterminal table are still there.
If I do another TestNg later, just retrieving my applicatifDo by his Id this time it gets the four elements.
Then there a big integrity problem here, and still I always use eagerly fetching. Any idea why such problem here ? And how could I make my cascading works ?
Third :
More globally, I have another cascading + orphanRemoval rules on other two entities and that works very well, but the entity target of these cascades does not have other relations with other entities.
Clearly, there is specific rules (or maybe limitations) when cascading on entities with other relationships.
Please do you know tutorials/rules explaining the best practices for such mappings ?
Thanks in advance. I'm stuck on this for too long.

EclipseLink merge unexpected cascade

I have two entity classes user and device.
User entity:
public class User {
private Long userId;
#OneToMany( mappedBy = "userId", fetch = FetchType.LAZY)
private Collection<Device> deviceCollection;
and device entity:
public class Device implements Serializable {
#JoinColumn(name = "user_id", referencedColumnName = "user_id")
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private User userId;
When I merge a previously detached device entity into the entity manager after the parent user has been deleted, both the (previously removed) user and the device are re-inserted into the database. There is no cascade annotation on user or device entity; therefore, I don't expect the user entity to be reinserted but it did;
How do I prevent the merge operation to cascade to the user entity?
Thanks in advance.
Any changes you do in detached state there is no possible way for Session Manager to know it so for it the changes are always new objects that needs to be merged (If you are calling merge)
So when you call merge it will load it from database so your object will have Prev+ new changes. So that is why mentioned behavior is happening.
What you can do is first load entity in the session apply changes and then call merge.
What you can do is something like below I have used similar relationship in one of my project with Eclipse Link
Query query = entityManager
.createNamedQuery("User.FindByUserId");
User fromDatabase = null;
try {
query.setParameter("userId", device.getUser().getUserId());
fromDatabase = (User) query.getSingleResult();
} catch (NoResultException noResultException) {
// There is no need to do anything here.
}
if (fromDatabase == null) {
User user= entityManager.merge(device.getUser());
device.setUser(user);
} else {
device.setUser(user);
}
entityManager.persist(device);
Try adding insertable=false, updatable=false to your JoinColumn, e.g.
#JoinColumn(name = "user_id", referencedColumnName = "user_id", insertable=false, updatable=false)
You should be using a version number to prevent entities from being mistakenly resurected. This will force an exception, where as the specification is a bit unclear on what should happen when merging over a relation that isn't marked cascade all or merge. The spec states that managed entities will be synchronized to the database, while the section dealing with merge implies that even entities referenced by relations without the cascade merge/all options will be managed afterward. This behavior is probably not what was intended, but shouldn't be relied on until clarified.
I had the same problem
and I found a bug about this: EntityManager.merge() cascading by default
but I really don't understand why this behaviour was never fix. It is one of reasons among others that I don't use EclipseLink (But it's not the point here)
Edit:
Chris, the comment which begin with "I'm not an expert" the argument that is put in head is not right, I think. What I understand, it's just that entity with a relation without cascade=MERGE or cascade=ALL, you can just navigate, that's all.
Otherwise why use Merge annotation ? It doesn't make sense.