1

我有一个问题,我试图将实体重新插入到我的数据库中。用以下单元测试说明:

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

4

5 回答 5

4

你实际上并没有执行你的 SQLQuery,这应该可以解决问题

 IQuery sqlQry = NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON");
 object ret = sqlQry.UniqueResult();
于 2012-11-16T14:18:19.620 回答
3

只是想知道您在这里关于删除/重新添加而不是不删除而只是更新的逻辑....

但是,如果 NHibernate 妨碍了您并且您无法更改删除身份列,那么有一些可怕的解决方法......

如果你想添加一条记录,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

或者,如果您想在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();
于 2012-11-16T15:28:22.937 回答
2

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

问题是

  1. 我没有在 save 方法中明确指定 Id
  2. 即使我有,set 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();
    }
    
于 2012-11-16T16:59:21.027 回答
1

选择另一种密钥生成策略,您尝试做的是一个非常糟糕的主意。标识列是一个人工主键,它不应该有任何意义。

于 2012-11-16T14:57:28.003 回答
0

不得不说,这个问题困扰了我很久。即使通过我之前执行 sql "SET IDENTITY_INSERT dbo.IdentityInsertTest ON" 然后运行 ​​Nihbernate 代码,它仍然无法正常工作。有2点需要采取更多的attation。

首先,您必须在代码中使用 Transaction。

NHibernate.ITransaction txn;
using (txn = SelectSession1.BeginTransaction())
{
    NHibernateSession2.CreateSQLQuery("SET IDENTITY_INSERT dbo.IdentityInsertTest ON").UniqueResult();

    ...

    NHibernateSession2.Flush();
    txn.Commit();
}

其次,必须使用"Id(x => x.Id).GeneratedBy.Assigned().Column ( "Id");" 在您的映射部分。

于 2015-07-30T02:27:49.763 回答