Win a copy of The Little Book of Impediments (e-book only) this week in the Agile and Other Processes forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Merge works without cascade=CascadeType.Merge ?

 
Himai Minh
Ranch Hand
Posts: 1361
7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, to my surprise, this merge works even though the cascade=CascadeType.Merge is not there.









Suppose I want to replace the following Gloria's record by the new employee2's data.
Originally, Gloria is from department 1 with phone number id =2 , like this:

After I execute the "Merge",
the record becomes 2, default, 0, 3, 5 for id, name, salary, department_id, phone_id.

A phone id=5 with values 000-000-0000  is created and then merged to Gloria's record.

To my surprise, why the phone number can be merged successfully without cascadeType.Merge in the phone attribute in Employee?
 
Frits Walraven
Creator of Enthuware JWS+ V6
Saloon Keeper
Pie
Posts: 2534
113
Android Chrome Eclipse IDE
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I haven't tried your example but I am also surprised. I had a look at the JPA specifications and I think it might be because of this last part:

3.2.7.1 Merging Detached Entity State
.... left out the beginning ....

  • If X is an entity merged to X', with a reference to another entity Y, where cascade=MERGE or cascade=ALL is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.


  • What do you think?
     
    Himai Minh
    Ranch Hand
    Posts: 1361
    7
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I think Glassfish does not follow the spec.

    If it follows the spec,
    Employee  X has a child Phone Y. If it is merged to another Employee X' with Phone Y' in the persistence context, the Phone Y should not be merged with the Y' of X'.
     
    Frits Walraven
    Creator of Enthuware JWS+ V6
    Saloon Keeper
    Pie
    Posts: 2534
    113
    Android Chrome Eclipse IDE
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Yes, EclipseLink (default JPA provider) doesn't follow the specifications on this point.

    I have tested your example and I got to the same output: the Phone entity was persisted (!?!?).  Instead the persistence provider should have thrown an IllegalStateException, just like when you change line 15 of EmployeeService into em.persist(employee2);

    If have reread the following part a couple of times and I am pretty sure they made a mistake implementing it:
    If X is an entity merged to X', with a reference to another entity Y, where cascade=MERGE or cascade=ALL is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.

    What is meant here (well the specs are not clear, but that is how I understand it) is that if there is no cascade specified that the only attribute that will be updated is the foreign key column to Y in X. Changes to Y won't be merged, but changes in X with regard to the relationship of Y will be updated in the database. Precondition here is that there is a row in the database reflecting Y.

    Following your example:

    and

    When you run this you will see that the call to service.merge(notManaged); will update the foreign key column EMPLOYEE.PHONE_ID, but it won't change the PHONE.PHONENUMBER.
     
    Himai Minh
    Ranch Hand
    Posts: 1361
    7
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi, Frits,
    Thanks so much for your suggestion.
    I tried your code and I tried both cases with and without line 22 emp.persist(phone) (to persist the phone number 33333333);



    Originally the data are (2, Gloria, 5000, 3, 2)
    I got this change in Employee table:

    id      name             salary        department_id      phone_id
    -----------------------------------------------------------------------
    2       Default               0                    100            12

    when Phone table is showing:


    id        phonenumber
    --------------------------
    2            3031231234
    10          0000000000
    12          3333333333

     
    So, my result is the employee Default has phonenumber changed from  3031231234 to 000000000 and then to 3333333.
     
    Himai Minh
    Ranch Hand
    Posts: 1361
    7
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi, Frit, I made another change to set the id of the phone:






    Output:

    id  name  salary department_id phone_id
    ------------------------------------------------
    2   Gloria  5000     1000                3




    //Explanation: the phone number is merged as the CascadeType.Merge is specified for the phone. That is why it is changed from 0000000 to 3333333.
    id phonenumber
    -------------------
    1    2021231234
    2    3031234567
    3    33333333333

     
    Himai Minh
    Ranch Hand
    Posts: 1361
    7
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi, I made a small change in the employee  by removing the CascadeType.MERGE for the phone:

    The merge method keeps the same:



    // Explanation : The phone number is not changed from 00000000 to 3333333 as the phone (id=3) is not persisted and not merged to the original phone.
    phone  table
    id    phonenumber
    ---------------------
    3      0000000000



    id name salary department_id phone_id
    -----------------------------------------------
    2  default 50000  100                3

     
    Himai Minh
    Ranch Hand
    Posts: 1361
    7
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Background:
    Department and employee has a one to many relationship.
    employee and phone has a one to one relationship.

    Department is merged as it is a parent of employee.
    But phone may or may not be merged as it is a child of employee.

    Gloria 's department is 2 and phone number is 2021231234.

    So far, we have 4 merge cases:

    case 1:
             
    Phone has cascade type= merge or not merge   
    employee2 has phone number set to 0000000
    employee2 merge happens. Department is changed to 100.
    Gloria's phone number is set to 0000000

    case 2:
    Phone has cascade type = merge
    employee2 has phone number id=10 set to 000000000.
    employee2 merge happens.
    notManaged employee is set to a new phone id=12 with number 333333333.
    notManaged merge happens. Department is changed to 100.
    Gloria's phone number is set to 333333333.

    case 3:
    Phone has cascade type = merge
    employee2 has phone number id=3 set to 00000000.
    notManaged is set to a new phone id=3  with number 33333333.
    notManaged merge happens. Department is changed to 100.
    Gloria's phone number is set to 33333333.

    case 4:
    phone has cascade type = not merge
    employee2 has phone number id=3 set to  00000000.
    notManaged is set to a new phone id=3 with number 33333333.
    notManaged merge happens. Department is changed to 100.
    Gloria's phone number is set to 0000000.
     
    Frits Walraven
    Creator of Enthuware JWS+ V6
    Saloon Keeper
    Pie
    Posts: 2534
    113
    Android Chrome Eclipse IDE
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    The merge bug was already reported some time ago: https://bugs.eclipse.org/bugs/show_bug.cgi?id=247662

    Added our discussion as a comment to it and voted it to be solved.
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic