Force query execution without flush/commit

Hi i am using the transaction-per-request (session-in-view) pattern for an asp.net web application. I have a couple of points in the application where i want to Save an NHibernate managed entity and then do a couple of more inserts and updates using common sql. These inserts/updates depend on the ID that the NH saved entity will take.

The problem is that the generated id does not exist in the transactions' scope. If i force a flush/commit the id is persisted but if the inserts/updates fail i have to rollback but the flushed/committed entity will not. Currently I'm doing a manual insert for these cases but that is something i want to change. So, is there a way to execute the SQL statement (inside the already open transaction) after the Save() but without forcing a flush/commit?

EDIT: I'm adding a semi-pseudocode example, i got 4 wrong answers so i think people don't understand (how NHibernate works) At the Begin request i issue a

nhsession.BeginTransaction()

then at some point i do

FooClass fc = new FooClass("value");
nhsession.Save(fc);
ITransaction trans = nhsession.Transaction;
SqlCommand sc = new SqlCommand("some insert/update query that depends on fc's id", (SqlConnection)nhsession.Connection);
sc.Parameters.Add("id", fc.Id); //NHibernate generates the id, note i'm using assigned/hi-lo so no round trip to the db takes place
transaction.Enlist(sc);
try {
    sc.ExecuteNonQuery();
}
catch (SqlException ex){
    transaction.RollBack();
    nhsession.Close();
}

and at the end of the Request i issue a CommitTransaction() and nhsession.Close()

Now this will do absolutely nothing: the FooClass (fc) has not been flushed/commited to the database. The Save() operation that NH has done is up to that point in-memory. That means no sql command has been issued by nhibernate and that means that the SqlCommand (sc) that i fire afterwards will fail miserably as the id does not exist.

If i do a flush/commit between Save() and the SqlCommand the FooClass(fc) _cannot_be_rolled_back_ and that is a bad bad thing. Currently, for this to work i make vanila sql insert using an SqlCommand , and i want to change that. (Why? because i don't want to make vanilla inserts they are susceptible to errors due to schema/model changes, and i got the OR/M for that)

How? i want to notify NHibernate somehow to execute the SqlCommand to corresponds to the Save() insert (hell, it can do all the SqlCommands it has gathered) but without it commiting or flushing!.

Currently i'm also searching for the prepared sql statement that nhibernate produces when flushing/commiting a saved object. Maybe i can just take that string and run it in my SqlCommand that is enlisted in the Transaction.


也许我不明白,但你不能这样做...

using(var tx = session.BeginTransaction())
{
    session.Save(entity);
    session.Flush();

    //perform non NH operations with entity.id

    tx.Commit();
}//uncommitted transaction would be rolled back on dispose()

Can you not use nested transactions or transaction scopes to support this?

Essentially what you are asking is for nh to assign the id before you use it, generated ids are only assigned when changes are flushed, changes are flushed only at transaction boundaries therefore can you not create an inner transaction scope to wrap the nh related persistence forcing the flush and id generation but still allowing the outer transaction to fail and roll back all work if one of the stored procedures fail.

How do I do nested transactions in NHibernate? has some sample code that demos an approach using scopes.


Sounds like you want ´dirty read´ isolation level during your transaction. This will allow you to read ´uncommited´ but ´saved´ content. I´m however not fluent enough in NHibernate to give any insight on how to do it there.

I´m sure someone else can hook in on how to do ´dirty read´ isolation level for NH.

链接地址: http://www.djcxy.com/p/23236.html

上一篇: NHibernate的儿童会议不正常冲洗

下一篇: 强制执行查询而不刷新/提交