在这个示例控制台应用程序中,我想更新表中的一行,然后在同一个表中插入另一行。
表格就像这样
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(?);选择SCOPE_IDENTITY()] ---&gt; System.Data.SqlClient.SqlException:无法在对象'dbo.Basket'中插入具有唯一索引'IX_Basket'的重复键行。
如果我刷新会话(注释掉的行)它可以工作,但为什么这是必要的?
我不想刷新会话并让Commit()处理它。
答案 0 :(得分: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();
}
这是因为您再次添加相同的唯一值。当然,您之前更改了现有值,但在刷新会话之前,这不会存储到数据库中。
会话在以下情况下刷新:
当您调用“保存”或“更新”时,NH会对数据库执行更新或插入,这是一种常见的误解。不是这种情况。刷新会话时执行插入和更新。 (有一些例外情况,例如使用原生ID时。)