2

次の制約を使用して挿入または更新を実行することは可能ですか?

  1. Dapperはプロジェクトで使用されています
  2. 主キーは正の自動インクリメントです
  3. 新しく挿入されたデータにはPK 値がない0(または の値がある)可能性があります
  4. データには、新しく挿入された行の PK 値が必要です。
  5. クエリは手続き的に生成されており、一般化することが望ましい

何かのようなもの :

int newId = db.QueryValue<int>( <<insert or update>>, someData );

私はさまざまな解決策について読んだことがありますが、最良の解決策は次のようです

merge tablename as target
using (values ('new value', 'different value'))
    as source (field1, field2)
    on target.idfield = 7
when matched then
    update
    set field1 = source.field1,
        field2 = source.field2,
        ...
when not matched then
    insert ( idfield, field1, field2, ... )
    values ( 7,  source.field1, source.field2, ... )

しかし

  1. 3番目の制約で失敗したようで、
  2. 新しく生成された ID を返すことは保証されません。

5 番目の制約 (または好み) のために、ストアド プロシージャは過度に複雑に見えます。

可能な解決策は何ですか?ありがとう!

4

1 に答える 1

3

テーブルに自動インクリメント フィールドがある場合、レコードを挿入するときにそのフィールドに値を割り当てることはできません。できますが、通常は悪い考えです:)

T-SQLMERGEステートメントを使用すると、デフォルトの無効な ID 値を含むすべての値をソース テーブルに入れ、insert 句を次のように記述できます。

when not matched then
    insert (field1, field2, ...)
    values (source.field1, source.field2, ...)

: 出力句を使用して、挿入された ID 値を取得します。

OUTPUT inserted.idfield

そうは言っても、特に多くのフィールドを持つテーブルの場合、SQL コードの生成が少し複雑になる可能性があると思います。多くの場合、個別UPDATEINSERTクエリを生成することをお勧めします...特に、変更されたフィールドのみを更新できるように、オブジェクトへの変更を追跡する方法がある場合。

MS SQL で作業していると仮定するとSCOPE_IDENTITY()、ステートメントの後に functionを使用INSERTして、複合ステートメント内のレコードの ID フィールドの値を取得できます。

INSERT INTO tablename(field1, field2, ...)
VALUES('field1value', 'field2value', ...);
SELECT CAST(SCOPE_IDENTITY() AS INT) ident;

この SQL ステートメントを実行すると、ID が 1 つの列に挿入された結果セットが返されます。あなたのdb.QueryValue<int>呼び出しは、あなたが求めている値を返します。

標準の整数自動インクリメント フィールドの場合は、上記で問題ありません。他のフィールド タイプの場合、またはより一般的なケースの場合は、SCOPE_IDENTITY()結果をキャストしVARCHAR(MAX)て、結果の文字列値を ID 列が期待するタイプ (GUID など) に解析してみてください。

db一般的なケースでは、クラスでこれを試してください:

public string InsertWithID(string insertQuery, params object[] parms)
{
    string query = insertQuery + "\nSELECT CAST(SCOPE_IDENTITY() AS VARCHAR(MAX)) ident;\n";
    return this.QueryValue<string>(insertQuery, parms);
}

および/または:

public int InsertWithIntID(string insertQuery, params object[] parms)
{
    string query = insertQuery + "\nSELECT CAST(SCOPE_IDENTITY() AS INT) ident;\n";
    return this.QueryValue<int>(query, parms);
}

そうすれば、挿入クエリを準備し、適切なInsertWithIDメソッドを呼び出して結果の ID 値を取得できます。それは運であなたの5番目の制約を満たすはずです:)

于 2013-04-05T06:03:18.157 に答える