Search code examples
mysqljakarta-eejpaeclipselink

JPA persistence updates


EclipseLink 2.5.2, NetBeans 8.0.2, Java 8, Derby: I have a DB structure with sort of a tree hierarchy and cross references using foreign keys. As an example it has the following key relationships

  • T1 is the parent.
  • T2, T3 & T4 are children of T1.
  • T5 is a child of T4

T1, T3 and T5 all have foreign keys to T2. Since that is instantiated in JPA as a class reference or Collections reference the memory of T2 is critical for these all to stay in sync.

I have verified that the following sequence changes that for T5 in my system

  1. new T5()
  2. T5.setT2(T1.getT2.get(0))
  3. em.persist(T5)
  4. T4.update(x, y, z)
  5. em.merge(T4)

Since T4 has a collection it appears that after step 5 above, EclipseLink has refreshed the value of T2 in T5 but at a different memory location that T1 and T3 are referring to.

Is this reasonable? I don't understand how to trust common references when the location of their data is not the same. Am I missing something?


I have upgraded to eclipseLink 2.6.0 and switched to MySQL and determined that this relates to another question I have posted about NULL's in a list. After months of research I can reproduce it easily but don't understand what I am doing wrong.

Somehow I am corrupting the persistence cache although the SQL and DB integrity are intact.

The application is about golf and to demonstrate there are 3 related entities: a Tournament, Players and Rounds. Tournament is the parent which contains a list of Players. Each Player has a foreign key back to the Tournament. A Player has a List of Rounds and each round have a FK back to the player.

When the Tournament is fully configured the organizer will hit a button to have Rounds created for each player. The Business layer (EJB) does the following:

  • em.merge(Tournament)
  • for each player
    • new round()
    • em.persist(round)
    • player.roundList.add(round)
    • em.merge(player)
  • em.merge(tournament)
  • em.find(tournament) - this is just there as a test to look at the revised reference pointers

All of this occurs during one instantiation of the business layer, the SQL generated is exactly what I would expect and the DB integrity is fine.

To reproduce I only need one player and one round and observe that after the em.update(player) the reference location for player in tournament is different than the reference location in round for the same player. My interpretation of this is that it has two memory reference for the same entity and indicates corruption in the persistence context.

The net result is that after returning from the EJB layer and re-reading the list of tournaments the same player may have rounds in their list which are NULL. There is something that occurs when the app starts as this either happens 100% of the time or NEVER with the exact same code and sequence to reproduce it. However after restarting the app the data that was saved is fine.

My business requirement must be common so I assume I am doing something wrong. However other than perhaps em.update(player) that is probably unnecessary I don't know what it is. Any help would be appreciated.


Solution

  • The EntityManager context will maintain object identity for you for all entities read in through it. But each EntityManager is meant to be used like you would a transaction, so changes made to entities in one transaction are not reflected in entities read in from another EntityManager unless the transaction is committed and the entities are refreshed. This is one of the reasons they are meant to be lightweight and obtained as needed, and it is not a good idea to cache entities around after the context itself is no longer used.
    You will run into problems when you work with objects read in from different contexts, as X' may not be the same instance of X even though they have the same identity - you might try to avoid passing around objects read in from different contexts as much as possible, and instead fetch the entity when required to make your changes.