Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Very strange "primary key [null]" validation exception("primary key [null]" exception appear where it should not)
Very strange "primary key [null]" validation exception [message #893590] Wed, 04 July 2012 17:48 Go to next message
Rodion Missing name is currently offline Rodion Missing nameFriend
Messages: 8
Registered: September 2009
Junior Member
I'm using eclipselink v 2.3.2 (supplied with glassfish v.3.2)
I've got this stack while trying to merge object graph into database:

Exception [EclipseLink-7197] (Eclipse Persistence Services - 2.3.1.v20111018-r10243): org.eclipse.persistence.exceptions.ValidationException
Exception Description: Null or zero primary key encountered in unit of work clone [com.hospitality.hp.osloproject.entities.contacts.info.PhoneContactInfo@75c191a7], primary key [null]. Set descriptors IdValidation or the "eclipselink.id-validation" property.
	at org.eclipse.persistence.exceptions.ValidationException.nullPrimaryKeyInUnitOfWorkClone(ValidationException.java:1439)
	at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChanges(DeferredChangeDetectionPolicy.java:107)
	at org.eclipse.persistence.descriptors.changetracking.DeferredChangeDetectionPolicy.calculateChangesForExistingObject(DeferredChangeDetectionPolicy.java:54)


My entities model looks like these:
@Entity
public class PhoneContactInfo {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_PROFILE_ENTITES")
  private Integer id;
  ...
}

@Entity
public class PersonContactableProfile extends ContactableProfile{
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_PROFILE_ENTITES")
  private Integer id;
  
  @OneToOne(cascade = {CascadeType.ALL}, orphanRemoval = true, optional = true)
  private PhoneContactInfo phoneInfo;

  @OneToOne(optional = false, cascade = CascadeType.ALL)
  private Person person;
  ...
}

@Entity
public class UserContact {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_PROFILE_ENTITES")
  private Integer id;
  
  @OneToOne(optional = false, orphanRemoval = false, fetch = FetchType.EAGER)
  private ContactableProfile contactable;

  @ManyToOne(optional = false, fetch = FetchType.EAGER)
  private Person personOwner;

  ...
}

@Entity
public class PersonToPersonLink {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_PROFILE_ENTITES")
  private Integer id;
  
  @ManyToOne(fetch = javax.persistence.FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
  private Person relative;

  @ManyToOne(fetch = javax.persistence.FetchType.LAZY)
  private Person user;
  
  ...
}

@Entity
public class Person {
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_PROFILE_ENTITES")
  private Integer id;

  @OneToMany(mappedBy = "personOwner", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
  private Set<UsersContact> contacts;

  @OneToMany(cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true, fetch = FetchType.LAZY)
  private Set<UserRelativeLink> relativeLinks;

  @OneToOne(optional = false, cascade = {CascadeType.ALL}, mappedBy = "person", fetch = FetchType.LAZY)
  private PersonContactableProfile personContactableProfile;

  ...
}


Every Person may have PersonContactable which is basically set of "ways to contact person" (e.g. phone number) - there is other types of contactable profiles in system, but this does not matter now. Every person can also may have collection of contacts and collection of relatives. UserContact entity, essentially, is record in one's contacts list. PersonToPersonLink keep link between two persons (e.g. relative). I have two Person instances, lets say Person1 and Person2. Person2 is already in Persons1's relstiveLinks collection (all data in database already). Then I take Person1, add new UserContact that points to Person2 PersonContactableProfile and also add new PhoneContactInfo to PersonContactableProfile of Person2 - I've got exception described above while saving Person1 graph (entityManager.merge(Person2)).

While investigating that issue i've found out why it happening - PhoneContactInfo instance added to cloneMapping collection of UnitOfWorkImpl twice!
First time during mapping traversal through contacts collection and second time during mapping traversal through relativeLinks collection. I do not understand if it's a bug? I also find out that line in MergeManager source code (trunk):

...
            Object registeredObject = unitOfWork.internalRegisterObject(clone, descriptor);//should use cloneAndRegisterNewObject to avoid the exist check
...


Addition of second copy of PhoneContactInfo to cloneMapping collection happening exactly during existence check.

Can someone tell me how I can fix this behaviour?
Re: Very strange "primary key [null]" validation exception [message #893755 is a reply to message #893590] Thu, 05 July 2012 13:07 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris DelahuntFriend
Messages: 1039
Registered: July 2009
Senior Member
Can you set logging to Finest or ALL and post the log showing when merge is called? Encountering the same object twice shouldnt be a problem, what needs to be determined is why it thinks it is existing instead of new.
How are you adding the new PhoneContactInfo to the existing PersonContactableProfile? And how is Person2 read in?

Best Regards,
Chris
Re: Very strange "primary key [null]" validation exception [message #893830 is a reply to message #893755] Thu, 05 July 2012 15:34 Go to previous messageGo to next message
Rodion Missing name is currently offline Rodion Missing nameFriend
Messages: 8
Registered: September 2009
Junior Member
Hello, thank for response Smile

Quote:

How are you adding the new PhoneContactInfo to the existing PersonContactableProfile? And how is Person2 read in?


My example model is little bit oversiplified Smile but basically I do like that:
/* ----------- server code (java): -------- */
... this method invoked by client to get person data
public Person getPersonById(Integer id){
   Person person = entityManager.findById(id, Person.class);
   // here come some operations to force loading lazy collections from db
   return person; // graniteds serialization 
}
... this method is invoked to save graph
public void savePerson(Person person1) {
  /* person1 is came from client request deserialization - i.e. it is detached from persistence layer
     all object instances in passed graph contains all added by weawing fields and their values */  
  entityManager.merge(person1); // exception happens not here, but on transaction commit which will call "calculateChanges", but PhoneContactInfo added twice here
}

/* ------- client code (actionscript): --------- */

var person1:Person = personService.getPersonById(1); // simplified, because service call is really async
var person2:Person = person1.relativeLinks[0].relative; // simplified, just assume we have only one relative in collection and it will be our "person2";

/* adding contact */
var userContact:UserContact = new UserContact();
userContact.personOwner = person1;
userContact.contactable= person2.personContactableProfile;
person1.contacts.add(userContact); // assume that collection is not null which is not true for real life

/* adding phone */
var phone:PhoneContactInfo = new PhoneContactInfo();
phone.value = '123123123'; // all contactinfos has value, forgot to add superclass definition in previous example
person2.personContactableProfile.phoneInfo = phone;

/* at this moment object graph that have person1 as "root" contains new userContact 
   person2 (which is also part of this object graph) have brand new phone number 
   time to submit all that stuff to server
*/
personService.savePerson(person1);



Quote:

Can you set logging to Finest or ALL and post the log showing when merge is called?


Log for FINEST level is hidden under spoiler. As i said model example is oversimplified, so you would not find exact matching in log.
Log excerpt

[Updated on: Thu, 05 July 2012 15:43]

Report message to a moderator

Re: Very strange "primary key [null]" validation exception [message #894772 is a reply to message #893830] Tue, 10 July 2012 13:19 Go to previous messageGo to next message
James Sutherland is currently offline James SutherlandFriend
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Can you set the log level to finest.

Also try removing the creation of the UserContact from the code to see if it is affecting the merge. It may be some cyclic issue.


James : Wiki : Book : Blog : Twitter
Re: Very strange "primary key [null]" validation exception [message #894814 is a reply to message #894772] Tue, 10 July 2012 15:56 Go to previous messageGo to next message
Rodion Missing name is currently offline Rodion Missing nameFriend
Messages: 8
Registered: September 2009
Junior Member
Quote:

Can you set the log level to finest.


Here is my log. Previous wasn't really with FINEST level because I miss one place where log level is actually was set.

Toggle Spoiler

Quote:

Also try removing the creation of the UserContact from the code to see if it is affecting the merge. It may be some cyclic issue.


If I don't create UserContact along with PhoneContactInfo it work like a charm - i.e. only UserContact and only PhoneContactInfo both works perfectly. This is some cyclic issue indeed, not like exactly "cyclic" but more like existence of several pathes through graph to same entity.

[Updated on: Tue, 10 July 2012 16:02]

Report message to a moderator

Re: Very strange "primary key [null]" validation exception [message #895377 is a reply to message #894814] Thu, 12 July 2012 15:38 Go to previous messageGo to next message
Rodion Missing name is currently offline Rodion Missing nameFriend
Messages: 8
Registered: September 2009
Junior Member
Anybody know the answer?
Re: Very strange "primary key [null]" validation exception [message #899659 is a reply to message #895377] Wed, 01 August 2012 17:20 Go to previous message
James Sutherland is currently offline James SutherlandFriend
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Your model is pretty complex, you may wish create a bug and attach your test, by first simplifying it as much as possible.

Also try change the merge cascade on your UserContact contactable to cascade the merge and persist.



James : Wiki : Book : Blog : Twitter
Previous Topic:difference between PESSIMISTIC_WRITE and read?
Next Topic:Postgresql NULLS FIRST Order by
Goto Forum:
  


Current Time: Fri Nov 28 09:00:18 GMT 2014

Powered by FUDForum. Page generated in 0.02456 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software