Java Forum / General / January 2008
[Hibernate] AssertionFailure null id in entry
Stefanie Ertheld - 21 Jan 2008 22:32 GMT [b]Hibernate version:3.2[/b]
[b]Name and version of the database you are using:Mysql 4[/b]
Hi, I got a Table I want to insert data into. It's primary key is an auto increment id. Addionally, it has a unique key, that is based on two columns. When I try to insert a row that contains data that would violate the unique key constraint, I get an error like: AssertionFailure null id in entry
This is really weird, as this doesn't really seem to have anything to do with the unique key???
Well, I am thinking - the Hibernate Model class uses Hibernate assertions to model the table's structure, but the info of the unique key was left out (legacy code! ;-). Could this be the reason for the hard to understand error "null id in entry"? Maybe Hibernate tries an insert, doesn't expect any violation as it doesn't know of the unique key that exists on the table, then it maybe tries to retrieve the automatically generated id Integer, which can not be generated, and maybe THIS produces the error I receive?
Maybe you have an explanation that makes more sense???
Thanks in advance!
Lew - 21 Jan 2008 23:28 GMT > [b]Hibernate version:3.2[/b] > [quoted text clipped - 9 lines] > This is really weird, as this doesn't really seem to have anything to do > with the unique key??? There are two unique keys. It has to do with one of them.
> Well, I am thinking - the Hibernate Model class uses Hibernate > assertions to model the table's structure, but the info of the unique [quoted text clipped - 6 lines] > > Maybe you have an explanation that makes more sense??? Your explanation makes the most sense to me. You aren't specifying any value for the id, and Hibernate apparently doesn't have any @Id notation for that id, so the inserts are trying to give a NULL value for the id, it seems. Why MySQL doesn't cover that is a mystery to me - maybe Hibernate is explicitly trying to insert NULL for the id, thus defeating the id sequencer and causing the "null id in entry".
Since you provide absolutely no code or error-message context it's only speculation on my part. If you provide an SSCCE [1] <http://www.physci.org/codes/sscce.html> or at least, uncut unedited error messages and the relevant table definitions and Hibernate annotations, we can help better.
[1] Andrew expands this as "Short, Self-Contained, Correct (Compilable) Example." I prefer "Compilable" to "Correct" for the expansion of the second "C". "Correct" in this instance means, "generates the error message of interest".
 Signature Lew
EricF - 22 Jan 2008 04:39 GMT >[b]Hibernate version:3.2[/b] > [quoted text clipped - 22 lines] > >Thanks in advance! You have to specify that the id is generated - there are several ways to do this, with annotation ...
@Id @GeneratedValue @Column(name = "ID")
Stefanie Ertheld - 22 Jan 2008 07:17 GMT Yes, of course I specified the id:
@Id @GeneratedValue(strategy=GenerationType.AUTO) private Integer id;
---
As I said, besides this unique auto increment key, the table also has a unique key, that however was not specified in the hibernate model class (legacy code). As the key is an auto increment id, you cannot violate it - however, you can violate the unique key. When this happens, I would expect an error like "ConstraintViolation" or so - but what I get in this case is: AssertionFailure null id in entry -
this is what I don't understand, and I wonder if the reason could be that hibernate doesn't know of my unique key constraint, tries to retrieve a new incremented id, this fails because of the unique key violation, and now as Hibernate didn't expect this to happen, it gets angry and spits out "AssertionFailure null id in entry"???
No idea, I am just guessing here. Will send you more code and the stack trace when at work.
Thanks in advance,
Stefanie
Lew - 22 Jan 2008 14:45 GMT > Yes, of course I specified the id: > > @Id > @GeneratedValue(strategy=GenerationType.AUTO) > private Integer id; Why do you say, "of course"? You gave no code samples, EricF's analysis is entirely consistent with your description of the problem, and you never mentioned that you had annotated the id in this way. No basis there for "of course".
I suggest that you read and follow <http://www.physci.org/codes/sscce.html>
 Signature Lew
Stefanie Ertheld - 22 Jan 2008 21:15 GMT Ok,
Here's my code:
Session hibernateSession = SessionFactoryUtils.getSession(getSessionFactory(), false); try { hibernateSession.save(MYOBJECT); } catch(ConstraintViolationException e) { //IGNORE EXCEPTION } catch (NestableRuntimeExcepion e) { //HANDLE AND LOG EXCEPTION LOG.severe(e); throw new MY_CUSTOM_EXCEPTION(e); }
I want to ignore when a duplicate key exception (or similar) occurs, but I want to log and handle all other errors.
What I don't understand is that when I get a Constraint Exception, it throws an "org.hibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs)".
I don't know what this means, nor do I know why it is still thrown - I looked up the AssertionFailure, it's a NestableRuntimeExcepion. And in its cache, I log the error, wrap it into my custom exception and throw this one instead - so how can there still be an AssertionFailure?
Thanks in advance,
Stefanie
EricF - 23 Jan 2008 04:26 GMT >Ok, > [quoted text clipped - 27 lines] > >Stefanie Can you show us what the type of MYOBJECT looks like? And the mapping file (unless the class is annotated).
Eric
Stefanie Ertheld - 23 Jan 2008 06:58 GMT EricF schrieb:
> Can you show us what the type of MYOBJECT looks like? And the mapping file > (unless the class is annotated). > > Eric MYOBJECT is the mapping file, and it is annotated. Will send the code tonight if still required.
However, more or less, it looks something like this:
@Entity @Table( name = "MYTABLE", catalog = "MYCATALOG", uniqueConstraints = { @UniqueConstraint( columnNames = { "COLUMN1", "COLUMN2" }) } ) public class MYOBJECT implements Serializable { private static final long serialVersionUID = -2360799711812618601L; protected Integer id;
@Id @GeneratedValue(strategy = GenerationType.AUTO) public Integer getId() { return this.id; }
public void setId(Integer id) { this.id = id; }
MORE SETTERS AND GETTERS
public equals()
public hashCode()
public stringToString()
}
Thanks in advance,
Stefanie
Stefanie Ertheld - 23 Jan 2008 17:23 GMT Ok, shortened, this is what my mapping class looks like:
@Entity (access=AccessType.PROPERTY) @Table(name= "MYTABLE", catalog= "MYCATALOG", uniqueConstraints= {@javax.persistence.UniqueConstraint(columnNames= {"MYROW1", "MYROW2", "MYROW3"})} ) public class DomainRegistration implements Serializable{
private Integer id; private String MYROW1; private String MYROW2; private String MYROW3;
@Id (generate=GeneratorType.AUTO) public Integer getId() { return this.id; }
public void setId(Integer id) { this.id = id; }
public String getMYROW1() { return this.MYROW1; }
@Column (insertable=true, updatable=true, name="MYROW1") public void setMYROW1(String MYROW1) { this.MYROW1 = MYROW1; }
public String getMYROW2() { return this.MYROW2; }
@Column (insertable=true, updatable=true, name="MYROW2") public void setMYROW2(String MYROW2) { this.MYROW2 = MYROW2; }
public String getMYROW3() { return this.MYROW3; }
@Column (insertable=true, updatable=true, name="MYROW3") public void setMYROW3(String MYROW3) { this.MYROW3 = MYROW3; }
public boolean equals(Object o) { if (this == o) return true; return false; }
public int hashCode(){ return -1;
}
public String toString(){ return ""; }
}
However, as stated before, when I have a duplicate unique key, it throws the weird error ("dont flush the session...") I stated above. Now deleted the id autoincrement field from my mapping class and used the unique key as a primary key, so I used an aditional mapping class just for this unique key - hmmmm makes me thinking - maybe the problem was that you ALWAYS need a separate mapping class for key - be it a primary, foreign or unique key - could this be the reason?!
Thanks in advance,
Stefanie
Stefanie Ertheld - 23 Jan 2008 17:25 GMT Ok, shortened, this is what my mapping class looks like:
@Entity (access=AccessType.PROPERTY) @Table(name= "MYTABLE", catalog= "MYCATALOG", uniqueConstraints= {...@javax.persistence.UniqueConstraint(columnNames= {"MYROW1", "MYROW2", "MYROW3"})} ) public class MYOBJECT implements Serializable{
private Integer id; private String MYROW1; private String MYROW2; private String MYROW3;
@Id (generate=GeneratorType.AUTO) public Integer getId() { return this.id; }
public void setId(Integer id) { this.id = id; }
public String getMYROW1() { return this.MYROW1; }
@Column (insertable=true, updatable=true, name="MYROW1") public void setMYROW1(String MYROW1) { this.MYROW1 = MYROW1; }
public String getMYROW2() { return this.MYROW2; }
@Column (insertable=true, updatable=true, name="MYROW2") public void setMYROW2(String MYROW2) { this.MYROW2 = MYROW2; }
public String getMYROW3() { return this.MYROW3; }
@Column (insertable=true, updatable=true, name="MYROW3") public void setMYROW3(String MYROW3) { this.MYROW3 = MYROW3; }
public boolean equals(Object o) { if (this == o) return true; return false; }
public int hashCode(){ return -1;
}
public String toString(){ return ""; }
}
However, as stated before, when I have a duplicate unique key, it throws the weird error ("dont flush the session...") I stated above. Now deleted the id autoincrement field from my mapping class and used the unique key as a primary key, so I used an aditional mapping class just for this unique key - hmmmm makes me thinking - maybe the problem was that you ALWAYS need a separate mapping class for key - be it a primary, foreign or unique key - could this be the reason?!
Thanks in advance,
Stefanie
EricF - 24 Jan 2008 05:52 GMT >Ok, shortened, this is what my mapping class looks like: > [quoted text clipped - 74 lines] > >Stefanie It would be easier to help if you were more precise. I searched the Hibernate source for the error you mentioned, didn't find anything, and then noticed the obvious typo.
The "don't flush" ... error only showed up 1 time, in DefaultFlushEntityEventListener.
Here's the code:
public void checkId(Object object, EntityPersister persister, Serializable id, EntityMode entityMode) throws HibernateException {
if ( id != null && id instanceof DelayedPostInsertIdentifier ) { // this is a situation where the entity id is assigned by a post-insert generator // and was saved outside the transaction forcing it to be delayed return; }
if ( persister.canExtractIdOutOfEntity() ) {
Serializable oid = persister.getIdentifier( object, entityMode ); if (id==null) { throw new AssertionFailure("null id in " + persister.getEntityName() + " entry (don't flush the Session after an exception occurs)"); } if ( !persister.getIdentifierType().isEqual(id, oid, entityMode) ) { throw new HibernateException( "identifier of an instance of " + persister.getEntityName() + " was altered from " + id + " to " + oid ); } }
}
Now Hibernate needs to do 2 things - it needs to persist an object to the database, and it needs to get the persisted values reflected in the object. I will not pretend to be a Hibernate expert - here's a few SWAGS:
Given that the class is called DefaultFlushEntityEventListener, Hibernate has decided it's time to do a flush - that is, actually commit your insert/update to the database. Given that the error occurs in the method checkId, it has nothing to do with the surrogate key you mentioned earlier.The id is null - and Hibernate does not know how to resolve it. If this is an update, it's a programming error. But it sounds like it's an insert.
The hashcode method in your class is scary. It returns a constant -1. This is bad. I don't know if it is relevant or not. Is there any chance this would cause Hibernate to do an update when an insert is expected? I dunno. Remove it or improve it. Seriously. No hashcode is better than this.
Hmm, looking at the Hibernate code again, I wonder if that is the issue. If the id was not null, it would return from the first if statement:
if ( id != null && id instanceof DelayedPostInsertIdentifier )
So the id is null.
So the persister thinks it can extract the id from the entity ..
if ( persister.canExtractIdOutOfEntity() ) {
Serializable oid = persister.getIdentifier( object, entityMode ); if (id==null) { throw new AssertionFailure("null id in " + persister.getEntityName() + " entry (don't flush the Session after an exception occurs)");
But it fails. I have not looked at the persister code. Again, a swag or 2 ...
1) Some thing is wrong with your code. Hibernate thinks the save is an update. It needs the id.
2) Something is wrong with the annotation. It looks ok to me, but I don't use MySql. At this point, we're talking about issues specific to the RDBMS used. How is Id defined in the database? Some serial type? Does MySql use sequences (Oracle and Postgres do)? Is this the appropriate annotation for a PK given it's datatype for MySql? I dunno.
But I do know that Hibernate's persistor thinks it can get the id from the object and fails.
HTH
Eric
Patricia Shanahan - 24 Jan 2008 06:04 GMT ...
> The hashcode method in your class is scary. It returns a constant -1. This is > bad. I don't know if it is relevant or not. Is there any chance this would > cause Hibernate to do an update when an insert is expected? I dunno. Remove it > or improve it. Seriously. No hashcode is better than this. ...
From a functional point of view, a constant hashCode is always safe. It is absolutely certain to return the same value for the same object, and to return the same value for equal objects.
It will also return the same code for unequal objects, but as the java.lang.Object documentation says "It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results."
Of course, a constant hashCode could cause performance problems by putting all keys in the same bucket of a hash-based data structure, but never a functional problem.
No hashCode has very different implications. It causes use of the inherited hashCode method, which presumably meets the requirements in combination with the superclass' equals method, but may not meet the requirements in conjunction with the current class equals method.
Patricia
Stefanie Ertheld - 24 Jan 2008 16:50 GMT Excactly. I don't know much a'bout Hibernate (I don't know much a'bout biology either! ;-), but I know the rules of equals and hashCode.
Besides, that's of course not my real code. I just "shortend" it, to show you I have a valid equals and a hashCode Method, just in case Hibernate needs em.
Stefanie
EricF - 25 Jan 2008 04:31 GMT >.... >> The hashcode method in your class is scary. It returns a constant -1. This is [quoted text clipped - 25 lines] > >Patricia Patricia,
Everything you say is correct. And I was probably mistaken with my comment. The constant hashcode would just be a performance problem. A constant equals would be more of a problem.
http://www.hibernate.org/109.html
Eric
Stefanie Ertheld - 24 Jan 2008 17:12 GMT 1. It's an insert - as far as I know - I call session.save(MYPERSISTENTOBJECT);
2. The id must be null - Hibernate tries to insert the data I send it - but fails, as a row that looks 100% the same besides its primary auto increment id, is already existing - unique key constraint violation.
3. Now I am catching the AssertionFailure and the application works as expected - but I am 100% there is something bad in my code, and I would like to find out and improve it, instead of catching and ignoring an "AssertionFailure".
4. As a test, I changed the persistent object so that I didn't have the auto increment id as primary key, but the unique key instead. Then, when trying to insert a duplicate value, I got a duplicate key error as expected - however then, when I tried a select * from TABLE where COL1 LIKE ... AND LIKE.. (using Hibernate Criterias) this then failed, with Hibernate telling me it couldn't find the column I specified. So I moved back to the code I got now. Not nice, but working (shaky!)
5. I am 99% sure the error is somewhere in my mapping object. The real equals and hashCode Method use all attributes of the unique key, and leave out the primary key - maybe that is wrong??? Maybe the should ONLY use the id, or maybe they should use the id AND the unique key attributes??
Thanks in advance,
Stefanie
Stefanie Ertheld - 24 Jan 2008 17:42 GMT P.s.: I am just reading this: http://www.hibernate.org/109.html
If I got it right, it says: Best practice: DONT use the id in equals and hashCode, use everything else - and that is just what I did, so that's probably not the problem??
Stefanie
Lew - 25 Jan 2008 00:09 GMT > P.s.: I am just reading this: > http://www.hibernate.org/109.html [quoted text clipped - 3 lines] > DONT use the id in equals and hashCode, use everything else - and that > is just what I did, so that's probably not the problem?? I don't know what your problem is, but I do know that auto-generated "id" fields are not part of the object model, and therefore most emphatically should not participate in the equals() and hashCode() logic.
Auto-generated keys are a convenience alias, and only an alias, for the real key of a table. They really should not be visible to business logic, certainly not above the DAO level. In technical terms, the autogenerated column is a surrogate key for the natural key of the table.
 Signature Lew
Lew - 25 Jan 2008 00:11 GMT > P.s.: I am just reading this: > http://www.hibernate.org/109.html [quoted text clipped - 3 lines] > DONT use the id in equals and hashCode, use everything else - and that > is just what I did, so that's probably not the problem?? Well, you don't want to literally use *everything* else in the object for the equals() and related calculations, just the key fields. (The ones that belong to the object model, not the auto-generated surrogate key of the physical database model.)
 Signature Lew
EricF - 25 Jan 2008 04:40 GMT >1. It's an insert - as far as I know - I call >session.save(MYPERSISTENTOBJECT); [quoted text clipped - 24 lines] > >Stefanie I realize there is a timelag with usenet, but it's difficult to help when the problem changes. ;-)
If you have a unique natural key, then I don't see much use for am auto-increment key. If you post the code and the error for the LIKE selection, you can get help about that issue.
Hibernate works just fine with auto-incremented keys if you want to go down that route. It's just a matter of figuring out the correct mapping given your DBMS.
Using all the attributes for equals and hashcode is not a good idea. Lew addresses that in another post - and review the link you posted earlier. http://www.hibernate.org/109.html
Eric
Lew - 25 Jan 2008 05:44 GMT > Using all the attributes for equals and hashCode is not a good idea > ... and review the link you posted earlier. > http://www.hibernate.org/109.html This link actually makes the same points, with the twist that they view the autogenned ID as the "real" key and the "natural" key from the business model as the candidate key. From the physical implementation standpoint, of course, they're absolutely right. From the modeling standpoint, that ID is merely a mechanism to capture the philosophical essence of identity.
There is a debate in the database community about natural keys versus artificial IDs. At one extreme people throw autogenned keys into where no serious thinker agrees they should go - e.g., as IDs for many-to-many table rows. At the other end a few believe that autogenned keys are anathema and should absolutely, positively never appear even in the physical data model.
The middle ground is that single-column INTEGER keys, autogenned or not, are a performance hack and a convenience. You use them to guard against rare but annoying changes in the natural keys (e.g., government ID number updates when someone goes into witness protection). They are faster than the typical multi-column natural key that is needed to match the object model. But these ID columns live only for the physical database - they do not participate in the logical or object model.
The referenced Hibernate article makes the same point - Hibernate is the data-mapping layer, so it knows about IDs, but it tries hard not to make its client layers deal with such under-the-hood details. IDs are pure mechanism, not model.
Thus the Hibernate article advises using the natural key to drive equals() and hashCode().
 Signature Lew
Stefanie Ertheld - 26 Jan 2008 12:44 GMT The code for the LIKE selection:
>return myHibernateSession.createCriteria(MYOBJECT.class) >.add(Expression.like(MYOBJECT.MYPROPERTYNAME, myCompareValue)).list();
I don't have the real thing at hand so I can't test it and so I neither have the exact error at hand - but doing some research and more thinking, I guess it was a PropertyNotFoundException.
Seems like Hibernate couldn't find MYOBJECT.MYPROPERTYNAME. What are the exact rules for the annotations? Do they have to be above the setter methods, above the getter methods, above both, or above the private instance variables. I put them abouve the private instance variables, because I think that makes it the easiest to read - and this worked for my insert statement - are there differences for the Like statement??? I also just read for the getter and setter methods, only the very first letter may and must be a capital letter - so it must be setHousenumber and getHousenumber NOT setHouseNumber and getHouseNumber. True? Pretty stupid imho. Maybe that was the reason??
Thanks in advance,
Stefanie
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|