我有一个问题,我试图将实体重新插入我的数据库。用以下单元测试说明:
// entity mapped to dbo.IdentityInsertTest table
// dbo.IdentityInsertTest has an IDENTITY Primary Key, Id
var id = (long)NHibernateSession1.Save(new IdentityInsertTest());
NHibernateSession1.Flush();
// delete previously created row
ExecuteNonQuery("DELETE FROM dbo.IdentityInsertTest");
try
{
// set entity insert off so that I can re-insert
NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult();
// re-create deleted row with explicit Id
NHibernateSession2.Save(new IdentityInsertTest { Id = id });
NHibernateSession2.Flush();
Assert.AreEqual(1, ExecuteScalar("SELECT COUNT(1) FROM dbo.IdentityInsertTest"));
// this assert fails: expected 1, actual 2
Assert.AreEqual(id, ExecuteScalar("SELECT TOP 1 [Id] FROM dbo.IdentityInsertTest"));
}
finally
{
NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest OFF").UniqueResult();
}
我的映射非常简单:
<class name="IdentityInsertTest" table="IdentityInsertTest">
<id name="Id" type="long">
<generator class="native" />
</id>
<property name="Data" type="int" not-null="false" />
</class>
就我所知,问题是NHibernate生成器仍以某种方式从SQL调用标识生成,即使我已将其关闭。有没有办法解决这个问题?
编辑:我最初忘记在设置IDENTITY_INSERT时执行“UniqueResult()”,但这似乎不是错误的根源。仍然得到相同的结果
答案 0 :(得分:4)
你实际上并没有执行你的SQLQuery,这应该可以解决问题
IQuery sqlQry = NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON");
object ret = sqlQry.UniqueResult();
答案 1 :(得分:3)
在这里想知道你关于删除/重新添加的逻辑,而不是删除而只是更新......
然而,如果NHibernate妨碍了你并且你无法更改删除Identity列,那么就会有一些可怕的工作......
如果您想在bottom
添加记录,那么您可以尝试: -
var sql = "DECLARE @id long = 0;
SELECT @id = MAX(Id) + 1 FROM IdentityInsertTest;
DBCC CHECKIDENT(IdentityInsertTest, RESEED, @id);";
NHibernateSession2.CreateSqlQuery(sql).ExecuteUpdate();
... now save the entity normally
OR 如果要在表的middle
中的某处添加记录,则必须手动构建SQL: -
var sql = "SET IDENTITY_INSERT dbo.IdentityInsertTest ON;
INSERT INTO IdentityInsertTest(Id, Data) Values (:id, :data)
VALUES (:id, :data);
SET IDENTITY_INSERT dbo.IdentityInsertTest OFF;";
NHibernateSession2.CreateSqlQuery(sql)
.SetInt64("id", id)
.SetInt32("data", data)
.ExecuteUpdate();
答案 2 :(得分:2)
注意:我已将此标记为答案,因为它直接回答了问题,但是,最后我使用了上面评论的软删除选项
问题在于
即使我有,设置的identity_insert也会在另一个查询中执行。通过使用交易来修复那个
// entity mapped to dbo.IdentityInsertTest table
// dbo.IdentityInsertTest has an IDENTITY Primary Key, Id
var id = (long)NHibernateSession1.Save(new IdentityInsertTest());
NHibernateSession1.Flush();
// delete previously created row
ExecuteNonQuery("DELETE FROM dbo.IdentityInsertTest");
try
{
NHibernate.ITransaction txn;
using (txn = SelectSession1.BeginTransaction())
{
// set entity insert off so that I can re-insert
NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult();
// re-create deleted row with explicit Id
NHibernateSession2.Save(new IdentityInsertTest(), id);
NHibernateSession2.Flush();
txn.Commit();
}
Assert.AreEqual(1, ExecuteScalar("SELECT COUNT(1) FROM dbo.IdentityInsertTest"));
// this assert fails: expected 1, actual 2
Assert.AreEqual(id, ExecuteScalar("SELECT TOP 1 [Id] FROM dbo.IdentityInsertTest"));
}
finally
{
NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest OFF").UniqueResult();
}
答案 3 :(得分:1)
选择另一种密钥生成策略,您尝试做的是一个非常糟糕的主意。标识列是一个人工主键,它不应该有任何意义。
答案 4 :(得分:0)
我不得不说,这个问题很长时间阻止了我。即使通过我exec sql&#34; SET IDENTITY_INSERT dbo.IdentityInsertTest ON&#34;之前然后运行Nihbernate代码,它是stil不起作用。有2点需要更多的支持。
首先,您必须在代码中使用Transaction。
NHibernate.ITransaction txn;
using (txn = SelectSession1.BeginTransaction())
{
NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult();
...
NHibernateSession2.Flush();
txn.Commit();
}
其次,您必须使用&#34; Id(x =&gt; x.Id).GeneratedBy。已分配()。列(&#34; Id&#34;);&# 34;在您的映射部分。