NHibernate - 使用identity_insert插入

时间:2012-11-16 13:52:01

标签: nhibernate 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
        {
            // 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()”,但这似乎不是错误的根源。仍然得到相同的结果

5 个答案:

答案 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)

注意:我已将此标记为答案,因为它直接回答了问题,但是,最后我使用了上面评论的软删除选项

问题在于

  1. 我没有在save方法中明确指定Id
  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;在您的映射部分。