[Hibernate] AssertionFailure null id in entry

S

Stefanie Ertheld

Name and version of the database you are using:Mysql 4

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!
 
L

Lew

Stefanie said:
Hibernate version:3.2

Name and version of the database you are using:Mysql 4

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???

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
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???

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".
 
E

EricF

Hibernate version:3.2

Name and version of the database you are using:Mysql 4

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!
You have to specify that the id is generated - there are several ways to do
this, with annotation ...

@Id @GeneratedValue
@Column(name = "ID")
 
S

Stefanie Ertheld

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
 
L

Lew

Stefanie said:
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>
 
S

Stefanie Ertheld

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
 
E

EricF

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

Can you show us what the type of MYOBJECT looks like? And the mapping file
(unless the class is annotated).

Eric
 
S

Stefanie Ertheld

EricF said:
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
 
S

Stefanie Ertheld

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
 
S

Stefanie Ertheld

Ok, shortened, this is what my mapping class looks like:

@Entity (access=AccessType.PROPERTY)
@Table(name= "MYTABLE", catalog= "MYCATALOG",
uniqueConstraints=
{[email protected](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
 
E

EricF

Ok, shortened, this is what my mapping class looks like:

@Entity (access=AccessType.PROPERTY)
@Table(name= "MYTABLE", catalog= "MYCATALOG",
uniqueConstraints=
{[email protected](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

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
 
P

Patricia Shanahan

EricF wrote:
....
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
 
S

Stefanie Ertheld

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
 
S

Stefanie Ertheld

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
 
S

Stefanie Ertheld

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
 
L

Lew

Stefanie said:
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??

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.
 
L

Lew

Stefanie said:
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??

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.)
 
E

EricF

EricF wrote:
....

....

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

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
 
E

EricF

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

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
 
L

Lew

EricF said:
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().
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top