-->
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.  [ 7 posts ] 
Author Message
 Post subject: SaveOrUpdateCopy doing Inserts although FlushMode = Commit
PostPosted: Mon Oct 15, 2007 10:17 am 
Newbie

Joined: Mon Oct 15, 2007 9:59 am
Posts: 6
Hi,

I'm still getting my head around NHibernate and have been dropped in it on a project that didn't really understand it either.

The system is a ASP.NET application which was doing an OpenSession on every call to the database and didn't have Lazy Loading working... performance was abysmal.

I'm trying to sort it all out and have implemented an Open Session In View pattern and am now correcting code to reconnect objects that are changed between page interactions with Lazy Loading turned on

e.g.

1) Object "Person" is updated by Page X
2) ASP.NET renders page. "Person" is saved in Session State.
3) User interacts with page
4) app reconnects Session State "Person" with NHibernate via "SaveOrUpdateCopy". App does some Lazy Loading work, changes object
5) ASP.NET renders page. "Person" is saved in Session State.
6) User interacts with page..... "save data"
7) app reconnects Session State "Person" with NHibernate via "SaveOrUpdateCopy". Code seperately calls 2nd SaveOrUpdateCopy within Transaction. App Commits.... data saved to database.

The following seems to work really well and in most cases doesn't actually write data until the transaction COMMIT as I have set the FlushMode of the session to COMMIT.

However, I've hit a situation that looks the same as everything else, except data is deleted then re-created exactly the same in child objects related to the parent via cascade="all-delete-orphan. After this has happened the 1st SaveOrUpdateCopy generates SQL Insert statements (but no deletes) for the new data.... even though it ISN'T in a transaction and a COMMIT hasn't taken place....

I'm very confused now... have I misunderstood how the SaveOrUpdateCopy works.... does it always write SQL no matter what the FlushMode is ?

Thanks


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 15, 2007 12:29 pm 
Regular
Regular

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

If you're working against a database that uses an Identity column for populating the primary key (f.e. SQLServer), NHibernate will always generate a the INSERT on the moment you're actually executing the SaveOrUpdate or SaveOrUpdateCopy because there's no other way to know what the new primary key is.

I don't know if this is the case (are you using SQLServer with an Identity column ?). If it is, this might explain it.

_________________
Please rate this post if it helped.

X.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 16, 2007 4:24 am 
Newbie

Joined: Mon Oct 15, 2007 9:59 am
Posts: 6
Yes I am, SQL Server 2005.

From what you say then that must be the reason but I must admit, I'm a little surprised. With Flushmode = commit, I'm in effect telling NHibernate that I decide when to write data... no? With the behaviour described, NHibernate thinks it knows better when obviously it doesn't - what if the user abandons changes? The data is already written to SQL..... so they can't.

A common thread in these forums seems to be that there is no way to reconnect an object that has changed back into the NHibernate cache and therefore continue to use Lazy Loading on it - without writing the changes back to the database. I almost can't believe this is true as it seems such an obvious requirement.... please tell me I'm stupid and the answer is obvious !

Many thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 16, 2007 5:00 am 
Regular
Regular

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

Don't worry : the INSERT is part of a transaction, so if the user decides to abandon his/her changes, the INSERT is rolled back.
NHibernate has to send the INSERT to the database, because there's no other way to set the Id of the object (which you might need after the SaveOrUpdate).

I thought about your second question and it certainly doesn't sound stupid to me. The only way that I know of to reattach a dirty object to a session is by using SaveOrUpdate(Copy) and this will generate INSERT statements for transient objects contained in collections (depending on the cascade options).

You might consider initializing all relevant collections of your object once you start to edit it, so that you aren't forced to lock it again until you're ready to persist it back to the database.

_________________
Please rate this post if it helped.

X.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 16, 2007 11:19 pm 
Regular
Regular

Joined: Wed Oct 25, 2006 10:51 pm
Posts: 71
xasp wrote:
NHibernate has to send the INSERT to the database, because there's no other way to set the Id of the object (which you might need after the SaveOrUpdate).


Just to clarify that, by default you will probably map 'identity' if you are using SQL Server. This is one of many strategies NHibernate can employ to generate id's automatically.

The problem with 'identity' strategy is that it has to do an INSERT before it will give you an id. So if your mapping has the 'identity' strategy (the default with SQLServer - you've probably got this or 'native') then it must do this. It's no choice. NHibernate is limited by the database's insert strategy.

If you are using Oracle, you can use the 'sequence' generation strategy which doesn't need to do an INSERT to get the next id.

Alternatively, there are other strategies you can use...
You can use GUID id generation, however I'm getting this by looking at a Hibernate book (not NHibernate so I'm not sure if NHibernate implements it).

Altogether, there are about 10 different id generation strategies you can map. 'Identity' is just one. And it's slightly odd by having to do an INSERT before it can provide the id.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 17, 2007 8:52 am 
Newbie

Joined: Mon Oct 15, 2007 9:59 am
Posts: 6
Ok thanks. That explains why, but its still a bit nuts.

Identity is a pretty common way of creating a non-business unique key and its also pretty common to create data for manipulation before I'm ready to confirm it. When I confirm it, that's when I want to go and do all the database updates/inserts etc. - not before as it's not "real" data until I confirm it.

With this processing strategy, in an detached environment such as ASP.NET, NHibernate will create data in the database for me regardless of what the application logic states - a major pain if the user thinks "oops, made a mistake - Cancel".

I don't agree with xasp that the data will be rolled back, because of the way the interactions with the database and any disconnected application works - changes will be commited at the end of an interaction - not at the end of a series of interactions (which is the processing model I'm describing).

It sounds like the only way to cope with this is to get data from an NHibernate connected object, load it into a specialised detached object, work on the detached object, then when ready, work out what has changed and update a connected NHibernate object with it. In the meantime you can use a (re)connected NHibernate object for Lazy Loading.

If I'm right then this sounds like a heck of a lot of work....


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 17, 2007 10:07 am 
Regular
Regular

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

When stating that the operation would be rolled back, I was effectively assuming you were updating your object as part of an active transaction. For example:
- start transaction
- bind your object to a session using SaveOrUpdate(Copy)
- initialize your collection
- rollback the transaction

I guess this might work, although I believe it would be easier to make sure the necessary associations and collections of your object are initialized before starting to manipulate it, so that you don't have to initialize lazy collections between the start of the manipulation and the commit of the changes by the user.

_________________
Please rate this post if it helped.

X.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 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.