These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Not same id in object as in table
PostPosted: Thu Dec 07, 2006 10:47 am 
Beginner
Beginner

Joined: Wed Nov 08, 2006 8:24 am
Posts: 26
Location: Gothenburg, Sweden
I have a problem with the received primary key when creating a new post in the database (using ISession->Save() or ISession->SaveOrUpdate()). The primary key in the created object is not the same as the key in the database (which is a Firebird database), the key in the database' table is always one higher than the key in by object. For instance: I debug my application, and when the Save()-method has executed I look into the object and find that SignId is 565, but when I check the database (after a commit) the id is 566.

The id part in the mapping XML-file look like this:
<id name="SignId" column="signid" type="int" unsaved-value="0">
<generator class="sequence">
<param name="sequence">signid_generator</param>
</generator>
</id>

And the generator declaration in the database' table is:
ACTIVE BEFORE INSERT POSITION 0
as
begin
new.SignId = gen_id(signid_generator, 1);
end

Does anyone know what is wrong?

Regards


Top
 Profile  
 
 Post subject: Re: Not same id in object as in table
PostPosted: Thu Dec 07, 2006 11:11 am 
Expert
Expert

Joined: Thu Jan 19, 2006 4:29 pm
Posts: 348
d95pari wrote:
The id part in the mapping XML-file look like this:
<id name="SignId" column="signid" type="int" unsaved-value="0">
<generator class="sequence">
<param name="sequence">signid_generator</param>
</generator>
</id>

And the generator declaration in the database' table is:
ACTIVE BEFORE INSERT POSITION 0
as
begin
new.SignId = gen_id(signid_generator, 1);
end

Does anyone know what is wrong?


The trigger, it should look like (psedocode, do not know the firbird syntax):
ACTIVE BEFORE INSERT POSITION 0
as
begin
if new.SignId IS NULL then
new.SignId = gen_id(signid_generator, 1);
end

_________________
If a reply helps You, rate it!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 08, 2006 8:49 am 
Regular
Regular

Joined: Thu Nov 23, 2006 10:29 am
Posts: 106
Location: Belgium
Hello,

Isn't the problem rather the fact that you're using a create-trigger at the same time as you're using a NHibernate-generator?

When you define a NHibernate generator, NHibernate will get the next sequence value, put it in the object and then save the object in the database (which will increase the id in the database once more).

I don't know if NHibernate has a way to cope with trigger-assigned id's, I myself always use the FireBird sequences but I agree this is a risk if you allow other applications to write to your database through ODBC for example (create triggers ensure the id's are being filled in).
You might consider using generator class="assigned", assign a dummy id to your class before saving it and immediately afterwards retrieve it back from the database. But this is really not an elegant workaround.

Maybe someone else on the forum knows of a better way.

X.
Please rate this post if it helped.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 08, 2006 8:58 am 
Regular
Regular

Joined: Thu Nov 23, 2006 10:29 am
Posts: 106
Location: Belgium
On second thought, "assigned" has also a risk : if the dummy-id you used already exists in the database, NHibernate will do an update instead of an insert.
So you should use values that will never exist in the database (f.e. negative values). But even then, NHibernate might first do a SELECT on the database to see if the object already exists before saving it (requires 1 more SQL statement).

Looking at the previous pseudocode from Gert I think that might well be the best solution : check in the trigger if the id is null or zero, if it is (row is inserted through ODBC for example): generate a new one. Otherwise: do nothing.

X.
Please rate this post if it helped.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 08, 2006 9:24 am 
Beginner
Beginner

Joined: Sat Apr 17, 2004 1:11 am
Posts: 36
You could always write a custom Id generator class that calls your stored procedure and use that in your mapping.

benster


Top
 Profile  
 
 Post subject: Re: Not same id in object as in table
PostPosted: Mon Dec 11, 2006 4:06 am 
Beginner
Beginner

Joined: Wed Nov 08, 2006 8:24 am
Posts: 26
Location: Gothenburg, Sweden
gert wrote:
The trigger, it should look like (psedocode, do not know the firbird syntax):
ACTIVE BEFORE INSERT POSITION 0
as
begin
if new.SignId IS NULL then
new.SignId = gen_id(signid_generator, 1);
end


Thanks gert, now it works like a charm. The actual Firebird-code is:

Code:
CREATE TRIGGER trgTTEST_BI_V3 for TTEST
active before insert position 0
as
begin
  if ((new.id is null) or (new.id = 0)) then
  begin
    new.id = gen_id( gidTest, 1 );
  end
end

See http://www.firebirdsql.org/manual/generatorguide-rowids.html

Regards


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.