NHibernate中的事务

编程入门 行业动态 更新时间:2024-10-25 10:29:25
NHibernate中的事务 - UPDATE然后INSERT。(Transactions in NHibernate - UPDATE then INSERT. What am I doing wrong?)

在此示例控制台应用程序中,我想更新表中的行,然后在同一个表中插入另一行。

桌子是这样的

CREATE TABLE [dbo].[Basket2]( [Id] [int] IDENTITY(1,1) NOT NULL, [UserId] [int] NULL ) ON [PRIMARY] CREATE UNIQUE NONCLUSTERED INDEX [IX_Basket] ON [dbo].[Basket2] ( [UserId] ASC )

所以基本上用户不能拥有2个篮子。

由于超出此帖子的原因,不得从表中删除任何篮子。 因此,当用户需要新的篮子时,旧的篮子只被设置为唯一的数字(id * -1)。

以下代码是模拟流程的示例应用程序 - 并且失败

private static void Main(string[] args) { ISessionFactory sessionFactory = CreateSessionFactory(); int userId = new Random().Next(); int basketId; using (var session = sessionFactory.OpenSession()) { using (var tx = session.BeginTransaction(IsolationLevel.ReadUncommitted)) { var newBasket = new Basket {UserId = userId}; basketId = (int) session.Save(newBasket); tx.Commit(); } using (var tx = session.BeginTransaction(IsolationLevel.ReadUncommitted)) { var basket = session.Get<Basket>(basketId); basket.UserId = basket.Id*-1; session.Save(basket); // comment in this line to make it work: //session.Flush(); var newBasket = new Basket {UserId = userId}; session.Save(newBasket); tx.Commit(); } } }

错误是:

未处理的异常:NHibernate.Exceptions.GenericADOException:无法插入:[ConsoleApplication1.Basket] [SQL:INSERT INTO [Basket](UserId)VALUES(?); select SCOPE_IDENTITY()] ---> System.Data.SqlClient.SqlException:无法在对象'dbo.Basket'中插入具有唯一索引'IX_Basket'的重复键行。

如果我冲洗会话(注释掉的行)它可以工作,但为什么这是必要的?

我宁愿不必刷新我的会话并让Commit()处理它。

In this sample console app I want to update a row in a table, and then insert another row in the same table.

The table is like this

CREATE TABLE [dbo].[Basket2]( [Id] [int] IDENTITY(1,1) NOT NULL, [UserId] [int] NULL ) ON [PRIMARY] CREATE UNIQUE NONCLUSTERED INDEX [IX_Basket] ON [dbo].[Basket2] ( [UserId] ASC )

So basically a user cannot have 2 baskets.

For reasons beyond this post baskets must not be deleted from the table. Therefore when a user needs a new basket the old one is just set to a unique number (id*-1).

The following code is a sample app that simulates the flow - and fails

private static void Main(string[] args) { ISessionFactory sessionFactory = CreateSessionFactory(); int userId = new Random().Next(); int basketId; using (var session = sessionFactory.OpenSession()) { using (var tx = session.BeginTransaction(IsolationLevel.ReadUncommitted)) { var newBasket = new Basket {UserId = userId}; basketId = (int) session.Save(newBasket); tx.Commit(); } using (var tx = session.BeginTransaction(IsolationLevel.ReadUncommitted)) { var basket = session.Get<Basket>(basketId); basket.UserId = basket.Id*-1; session.Save(basket); // comment in this line to make it work: //session.Flush(); var newBasket = new Basket {UserId = userId}; session.Save(newBasket); tx.Commit(); } } }

The error is:

Unhandled Exception: NHibernate.Exceptions.GenericADOException: could not insert: [ConsoleApplication1.Basket][SQL: INSERT INTO [Basket] (UserId) VALUES (?); select SCOPE_IDENTITY()] ---> System.Data.SqlClient.SqlException: Cannot insert duplicate key row in object 'dbo.Basket' with unique index 'IX_Basket'.

If I Flush the session (commented out lines) it works, but why is this necessary?

I would prefer not having to Flush my session and letting Commit() handle it.

最满意答案

您不需要保存/更新/ SaveOrUpdate任何已在会话中的实体。

但是你再次重复使用相同的id。 因此,请确保在之前刷新会话:

using (var tx = session.BeginTransaction(IsolationLevel.ReadUncommitted)) { var basket = session.Get<Basket>(basketId); basket.UserId = basket.Id*-1; // no save //session.Save(basket); // flush change on unique field session.Flush(); var newBasket = new Basket {UserId = userId}; // save new item which is not in the session yet session.Save(newBasket); tx.Commit(); }

这是因为您再次添加相同的唯一值。 当然,您之前更改了现有值,但在刷新会话之前,这不会存储到数据库中。

会话在以下情况下刷新:

你打电话给同花顺 在查询之前(Get和Load除外) 提交时(除了使用自己的ADO连接)

当您调用“保存”或“更新”时,NH会对数据库执行更新或插入,这是一种常见的误解。 不是这种情况。 刷新会话时执行插入和更新。 (有一些例外,例如,当使用本机ID时。)

You don't need to Save / Update / SaveOrUpdate any entities which are already in the session.

But you are reusing the same id again. So make sure that the session is flushed before:

using (var tx = session.BeginTransaction(IsolationLevel.ReadUncommitted)) { var basket = session.Get<Basket>(basketId); basket.UserId = basket.Id*-1; // no save //session.Save(basket); // flush change on unique field session.Flush(); var newBasket = new Basket {UserId = userId}; // save new item which is not in the session yet session.Save(newBasket); tx.Commit(); }

This is because you add the same unique value again. Of course you change the existing value before, but this is not stored to the database before the session is flushed.

The session is flushed when:

you call flush before queries (except of Get and Load) on commit (except you use your own ADO connection)

It is a common misunderstanding that NH performs update or insert on the database when you call Save or Update. This is not the case. Insert and update are performed when flushing the session. (There are some exceptions on that, eg. when using native ids.)

更多推荐

本文发布于:2023-08-04 11:08:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1414842.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:事务   NHibernate

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!