Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Merge behavior
Merge behavior [message #1071091] Fri, 19 July 2013 06:29 Go to next message
Marco Quaranta is currently offline Marco Quaranta
Messages: 6
Registered: July 2013
Junior Member
Hello,
I'd like to know if behaviour I'm going to explain is correct.
I've a Parent with several Collection<Child> relationship (@OneToMany, lazy fatch and no cascade).
Merging Parent makes Eclipselink executing several select statement, one for each child collections.

The code that issues these statements is in the method mergeIntoObject(Object target, boolean isTargetUnInitialized, Object source, MergeManager mergeManager, AbstractSession targetSession) class org.eclipse.persistence.mappings.CollectionMapping
in this line:

// BUG#5190470 Must force instantiation of indirection
containerPolicy.sizeFor(valueOfTarget);

Is this behavoir correct? I've experienced really low performance doing merge in this way.
My Eclipselink version is 2.3.2

Thanks,
Marco

[Updated on: Tue, 23 July 2013 03:19]

Report message to a moderator

Re: Merge behavior [message #1071292 is a reply to message #1071091] Fri, 19 July 2013 15:10 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris Delahunt
Messages: 995
Registered: July 2009
Senior Member
Are the collections on the object you are merging instantiated? If so, then it would need to trigger the collections on the managed entity to know what has changed for the merge operation.

Best Regards,
Chris
Re: Merge behavior [message #1072199 is a reply to message #1071091] Mon, 22 July 2013 05:22 Go to previous messageGo to next message
Marco Quaranta is currently offline Marco Quaranta
Messages: 6
Registered: July 2013
Junior Member
Hello Chris,
thank you for answering!

Collections on the object I'm merging are not instantiated (ie. references are null)...

However, I don't understand why entitymanager needs to trigger collections (instantiated or not) to know what has changed if I don't use cascade merge ...

Regards,
Marco
Re: Merge behavior [message #1072742 is a reply to message #1072199] Tue, 23 July 2013 08:09 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris Delahunt
Messages: 995
Registered: July 2009
Senior Member
Null is not the same as not triggered, but changes to the list still must be merged into the collection. Cascade merge means that the merge will cascade to the referenced entities, the re fences themselves are a part of the entity being merged directly.
Re: Merge behavior [message #1122159 is a reply to message #1071091] Tue, 01 October 2013 05:29 Go to previous messageGo to next message
Marco Quaranta is currently offline Marco Quaranta
Messages: 6
Registered: July 2013
Junior Member
Hello Chris,
I'm returning on this after a while .. is this behaviour compliant with JPA Spec 3.2.4.1 Merging Detached Entity State?

"The persistence provider must not merge fields marked LAZY that have not been fetched: it must ignore such fields when merging."

It seems to me that merging my entity is eagerly loading every Collection<Child> even if these are marked as lazy and not fetched.

Thank you,
Marco
Re: Merge behavior [message #1123386 is a reply to message #1122159] Wed, 02 October 2013 10:08 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris Delahunt
Messages: 995
Registered: July 2009
Senior Member
You said references are null, and I said null is not the same as not-fetched. How are they null? Null means they have been fetched or set to null, which means the merge process needs to trigger the collection on the managed entity to find out which entities are to be removed from the collection (through setting it to null).

Re: Merge behavior [message #1140240 is a reply to message #1071091] Wed, 16 October 2013 04:11 Go to previous messageGo to next message
Marco Quaranta is currently offline Marco Quaranta
Messages: 6
Registered: July 2013
Junior Member
Hello,
I'll try to explain using an example.
Suppose I have two entities: Student and Presentation.
Presentation has a FK to Student, on JPA layer there is a bidirectional relation between Presentation and Student.

@Entity
public class Student{
	...
	@OneToMany(mappedBy="student")
	private List<Presentation> presentations;
	private String firstName;
	private int yearjoined;
	...
} 

@Entity
public class Presentation{
	...
	@ManyToOne
	@JoinColumn(name = "STUDENT_ID")
	private Student student;
	private String topic;
	...
} 

I execute the following code:

Student s = new Student(); // Empty costructor does nothing (ie. does not initialize presentations)
s.setId(1);
s.setYearjoined(100);
em.merge(s);


Eclipselink will issues the following queries:

1) --SELECT ID, FIRSTNAME, LASTNAME, ROLLNUMBER, SCORE, DEPT, NUMBER, YEARJOINED FROM STUDENT WHERE (ID = ?)	-- bind => [1]
2) --SELECT ID, GRADED, MARKSOBTAINED, TOPIC, STUDENT_ID FROM PRESENTATION WHERE (STUDENT_ID = ?) -- bind => [1]
3) --UPDATE STUDENT SET FIRSTNAME = ?, LASTNAME = ?, ROLLNUMBER = ?, SCORE = ?, DEPT = ?, NUMBER = ?, YEARJOINED = ? WHERE (ID = ?) bind => [null, null, null, 0, null, null, 100, 1]


Now, the question is: is there a way to avoid the query number 2?
I'd like to not query the DB if my student has thousand or even million presentations.

I have tried the same with Hiberante and this is the output:

1) select student0_.id as id13_0_, student0_.dept as dept13_0_, student0_.number as number13_0_, student0_.yearjoined as yearjoined13_0_, student0_.firstname as firstname13_0_, student0_.lastname as lastname13_0_, student0_.rollnumber as rollnumber13_0_, student0_.score as score13_0_ from Student student0_ where student0_.id=?
2) update Student set dept=?, number=?, yearjoined=?, firstname=?, lastname=?, rollnumber=?, score=? where id=?


Why does Eclipselink need this query?

Thank you
Marco
Re: Merge behavior [message #1142221 is a reply to message #1140240] Thu, 17 October 2013 09:24 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris Delahunt
Messages: 995
Registered: July 2009
Senior Member
No Message Body

[Updated on: Thu, 17 October 2013 10:47]

Report message to a moderator

Re: Merge behavior [message #1142222 is a reply to message #1140240] Thu, 17 October 2013 09:25 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris Delahunt
Messages: 995
Registered: July 2009
Senior Member
Hello Marco

Using an empty stub is the problem. You are creating a student object and only setting the ID and yearjoined values. By calling merge with this empty stub, you wipe out every other value in the entity - merge is required to merge the state of your stub into the managed entity, including nulls. What you want instead is to get the entity from the EntityManager and make your changes to it. ie
Student s = em.find(Student.class, 1; 
s.setYearjoined(100);
em.flush();


Best Regards,
Chris
Re: Merge behavior [message #1145505 is a reply to message #1142222] Sat, 19 October 2013 11:18 Go to previous messageGo to next message
Marco Quaranta is currently offline Marco Quaranta
Messages: 6
Registered: July 2013
Junior Member
Hello Chris,
I know using em.find method (or even better em.getReference) I will update my entity but .. what I needed to know (and what I asked) is that it is possible, in Eclipselink, using merge. The problem is that I already have a lot of code written using this pattern: new Object, set Id and some properties, call merge. I'd like to not refactor what has already been written.

Thank you,
Marco
Re: Merge behavior [message #1148401 is a reply to message #1145505] Mon, 21 October 2013 09:31 Go to previous message
Chris Delahunt is currently offline Chris Delahunt
Messages: 995
Registered: July 2009
Senior Member
Up to now, you have not mentioned you are using a stub, and have been asking if it is JPA compliant. So to answer your prior questions, the merge behavior is expected and and required by the JPA specification - you have null values in your entity state that need to be merged into the managed Entity. If you check your managed entity after the merge, you will see it no longer has any presentations - the collection will now be null and your object model will no longer match what you have in the database.

I see what you are saying that the query isn't strictly needed, as this mapping does not really control the relationship, it could be ignored. Feel free to file a feature request to avoid instantiating the 1:m bidirectional collection on merge when its been nulled out, or even create your own 1:M class instance to use instead with the change. But your design will still result in your cache becoming corrupt or worse a loss of data with other mappings - the entity should be used, not an empty stub for the em.merge call. If you are unable to change the application, you could make your own merge method that uses em.find or getReference and then merges non-null attributes into the entity - allowing your app to still pass around stubs internally.

Best Regards,
Chris

[Updated on: Mon, 21 October 2013 09:32]

Report message to a moderator

Previous Topic:Full FetchGroup is NULL
Next Topic:Where are my EclipseLink JPA Facets?
Goto Forum:
  


Current Time: Thu Apr 24 15:05:45 EDT 2014

Powered by FUDForum. Page generated in 0.01921 seconds