NHibernate中的事务 - UPDATE然后INSERT.我究竟做错了什么?

Ras*_*mus 1 nhibernate transactions fluent-nhibernate

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

桌子是这样的

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
)
Run Code Online (Sandbox Code Playgroud)

所以基本上用户不能拥有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();
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

错误是:

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

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

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

Ste*_*ger 5

您不需要保存/更新/ 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();
        }
Run Code Online (Sandbox Code Playgroud)

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

会话在以下情况下刷新:

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

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