代码之家  ›  专栏  ›  技术社区  ›  Rasmus

NHibernate中的事务-更新然后插入。我做错什么了?

  •  1
  • Rasmus  · 技术社区  · 14 年前

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

    桌子是这样的

    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
    )
    

    所以基本上一个用户不能有两个篮子。

    下面的代码是一个示例应用程序,它模拟了流并失败

    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:插入到[Basket](UserId)值(?);选择范围\u IDENTITY()]--->System.Data.SqlClient客户端.SqlException:无法在对象“”中插入重复的键行dbo.篮子'具有唯一索引'IX_Basket'。

    我希望不必刷新会话并让Commit()处理它。

    1 回复  |  直到 14 年前
        1
  •  5
  •   Stefan Steinegger    14 年前

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

    但是

           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连接除外)