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からID生成を呼び出しているということです。これを回避する方法はありますか?

編集: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が邪魔になり、ID列の削除を変更できない場合は、いくつかの恐ろしい回避策があります...

でレコードを追加したい場合は、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. 私が持っていたとしても、設定された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

別のキー生成戦略を選択してください。あなたがやろうとしていることは本当に悪い考えです。ID列は人為的な主キーであり、意味を持たないようにする必要があります。

于 2012-11-16T14:57:28.003 に答える
0

私が言わなければならないのは、この問題が私を長い間妨げていたということです。前にSQL「SETIDENTITY_INSERTdbo.IdentityInsertTestON」を実行してからNihbernateコードを実行しても、動作しませんでした。より多くの注意を払う必要がある2つのポイントがあります。

まず、コードで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 に答える