【发布时间】:2010-02-16 17:51:33
【问题描述】:
您好,我正在为 asp.net Web 应用程序使用每请求事务(视图中的会话)模式。我在应用程序中有几点要保存 NHibernate 托管实体,然后使用通用 sql 进行更多插入和更新。这些插入/更新取决于 NH 保存的实体将采用的 ID。
问题是生成的 id 不存在于事务的范围内。如果我强制刷新/提交,则 id 将保留,但如果插入/更新失败,我必须回滚,但刷新/提交的实体不会。目前我正在为这些情况进行手动插入,但这是我想要改变的。那么,有没有办法在 Save() 之后执行 SQL 语句(在已经打开的事务中)但不强制刷新/提交?
编辑:我正在添加一个半伪代码示例,我得到了 4 个错误答案,所以我认为人们不明白(NHibernate 是如何工作的) 在开始请求我发出一个
nhsession.BeginTransaction()
然后在某个时候我会这样做
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();
}
在请求结束时我发出CommitTransaction() 和nhsession.Close()
现在这将完全没有任何作用:FooClass (fc) 尚未刷新/提交到数据库。 NH 已经完成的Save() 操作在内存中达到了这一点。这意味着 nhibernate 没有发出任何 sql 命令,这意味着我之后触发的 SqlCommand (sc) 将失败,因为 id 不存在。
如果我在Save() 和SqlCommand 和FooClass(fc) _cannot_be_rolled_back_ 之间进行刷新/提交,这是一件坏事。
目前,为了让它工作,我使用SqlCommand 进行 vanila sql 插入,我想改变它。 (为什么?因为我不想制作香草插入,它们容易因架构/模型更改而出错,我为此得到了 OR/M)
怎么样?我想通知 NHibernate 以某种方式执行 SqlCommand 以对应于 Save() 插入(地狱,它可以执行它收集的所有 SqlCommands)但没有它提交或刷新!。
目前我还在搜索 nhibernate 在刷新/提交保存的对象时生成的准备好的 sql 语句。也许我可以只使用该字符串并在事务中登记的 SqlCommand 中运行它。
【问题讨论】:
-
@Jaguar:我想我对这种情况的理解存在差距。我猜 Save() 方法为您提供了由 NHibernate 生成的 Id,无论它是 hi/lo 还是身份或其他。你不能只使用这个返回值吗?我不记得了,但我认为它是返回的持久对象。然后,调用 Save() 将提供您需要的 Id 值,然后在您的其他 SQL 语句 (sc) 中使用该值。否则,使用 ISession.CreateSQLQuery() 方法代替这个 SqlCommand 不是更好吗?这种方法可以让你直接对 DB 运行 SQL 语句
-
将您的 Save() 语句包含在您的事务中是否会有所帮助?那么当 Save() 返回 Id 时,您可以将其用于其他 SQL DML 语句吗?然后 Flush() 会话中的所有内容,因此如果您的 Insert (Save()) 失败,这将由您的事务的 Rollback() 方法自动回滚?
标签: c# asp.net nhibernate transactions