206

データベースへの挿入を実行し、挿入されたIDをDapperで返すにはどうすればよいですか?

私はこのようなことを試しました:

string sql = "DECLARE @ID int; " +
             "INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); " +
             "SELECT @ID = SCOPE_IDENTITY()";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).First();

しかし、それはうまくいきませんでした。

@Marc Gravell、返信ありがとうございます。私はあなたの解決策を試しましたが、それでも同じ例外トレースが以下にあります

System.InvalidCastException: Specified cast is not valid

at Dapper.SqlMapper.<QueryInternal>d__a`1.MoveNext() in (snip)\Dapper\SqlMapper.cs:line 610
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable`1 commandTimeout, Nullable`1 commandType) in (snip)\Dapper\SqlMapper.cs:line 538
at Dapper.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param) in (snip)\Dapper\SqlMapper.cs:line 456
4

9 に答える 9

356

を使用する場合、入出力パラメーター(値を含む)をサポートしますが、この場合、より単純なオプションは単純です。RETURNDynamicParameters

var id = connection.QuerySingle<int>( @"
INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff);
SELECT CAST(SCOPE_IDENTITY() as int)", new { Stuff = mystuff});

OUTPUTSQL Serverの最新バージョン(2005以降)では、次の句を使用できることに注意してください。

var id = connection.QuerySingle<int>( @"
INSERT INTO [MyTable] ([Stuff])
OUTPUT INSERTED.Id
VALUES (@Stuff);", new { Stuff = mystuff});
于 2011-11-25T14:07:03.813 に答える
56

KB:2019779、「SCOPE_IDENTITY() および @@IDENTITY を使用すると、正しくない値を受け取る場合があります」、OUTPUT 句が最も安全なメカニズムです。

string sql = @"
DECLARE @InsertedRows AS TABLE (Id int);
INSERT INTO [MyTable] ([Stuff]) OUTPUT Inserted.Id INTO @InsertedRows
VALUES (@Stuff);
SELECT Id FROM @InsertedRows";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();
于 2012-09-27T10:31:14.840 に答える
54

遅い回答ですが、最終的に使用した回答の代替は次のとおりです。 OUTPUT INSERTEDSCOPE_IDENTITY()

挿入されたオブジェクトの ID のみを返します:

挿入された行のすべてまたは一部の属性を取得できます。

string insertUserSql = @"INSERT INTO dbo.[User](Username, Phone, Email)
                        OUTPUT INSERTED.[Id]
                        VALUES(@Username, @Phone, @Email);";

int newUserId = conn.QuerySingle<int>(
                                insertUserSql,
                                new
                                {
                                    Username = "lorem ipsum",
                                    Phone = "555-123",
                                    Email = "lorem ipsum"
                                },
                                tran);

ID を持つ挿入されたオブジェクトを返します:

必要に応じて、挿入された行全体Phoneを取得できます。Email

string insertUserSql = @"INSERT INTO dbo.[User](Username, Phone, Email)
                        OUTPUT INSERTED.*
                        VALUES(@Username, @Phone, @Email);";

User newUser = conn.QuerySingle<User>(
                                insertUserSql,
                                new
                                {
                                    Username = "lorem ipsum",
                                    Phone = "555-123",
                                    Email = "lorem ipsum"
                                },
                                tran);

また、これにより、削除または更新された行のデータを返すことができます。トリガーを使用している場合は注意してください(前述のリンクから):

OUTPUT から返される列には、INSERT、UPDATE、または DELETE ステートメントが完了した後、トリガーが実行される前のデータがそのまま反映されます。

INSTEAD OF トリガーの場合、トリガー操作の結果として変更が行われなくても、INSERT、UPDATE、または DELETE が実際に発生したかのように、返される結果が生成されます。OUTPUT 句を含むステートメントがトリガーの本体内で使用されている場合は、テーブルの別名を使用して、トリガーによって挿入および削除されたテーブルを参照し、OUTPUT に関連付けられた INSERTED および DELETED テーブルで列参照が重複しないようにする必要があります。

ドキュメントの詳細:リンク

于 2017-11-04T11:51:52.690 に答える
7

取得しているInvalidCastExceptionは、SCOPE_IDENTITYがDecimal(38,0)であることが原因です。

次のようにキャストすることで、intとして返すことができます。

string sql = @"
INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff);
SELECT CAST(SCOPE_IDENTITY() AS INT)";

int id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();
于 2012-06-28T20:24:11.487 に答える
4

SQL 2000 に対して作業を行っているためかどうかはわかりませんが、これを機能させるためにこれを行う必要がありました。

string sql = "DECLARE @ID int; " +
             "INSERT INTO [MyTable] ([Stuff]) VALUES (@Stuff); " +
             "SET @ID = SCOPE_IDENTITY(); " +
             "SELECT @ID";

var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();
于 2012-04-18T21:01:07.057 に答える
1

SQLサーバーの回答が表示されます。ここでは、トランザクションを使用するMySqlの回答です


    Dim sql As String = "INSERT INTO Empleado (nombres, apepaterno, apematerno, direccion, colonia, cp, municipio, estado, tel, cel, correo, idrol, relojchecadorid, relojchecadorid2, `activo`,`extras`,`rfc`,`nss`,`curp`,`imagen`,sueldoXHra, IMSSCotiza, thumb) VALUES (@nombres, @apepaterno, @apematerno, @direccion, @colonia, @cp, @municipio, @estado, @tel, @cel, @correo, @idrol, @relojchecadorid, @relojchecadorid2, @activo, @extras, @rfc, @nss, @curp, @imagen,@sueldoXHra,@IMSSCotiza, @thumb)"
    
            Using connection As IDbConnection = New MySqlConnection(getConnectionString())
                connection.Open()
                Using transaction = connection.BeginTransaction
                    Dim res = connection.Execute(sql, New With {reg.nombres, reg.apepaterno, reg.apematerno, reg.direccion, reg.colonia, reg.cp, reg.municipio, reg.estado, reg.tel, reg.cel, reg.correo, reg.idrol, reg.relojchecadorid, reg.relojchecadorid2, reg.activo, reg.extras, reg.rfc, reg.nss, reg.curp, reg.imagen, reg.thumb, reg.sueldoXHra, reg.IMSSCotiza}, commandTimeout:=180, transaction:=transaction)
                    lastInsertedId = connection.ExecuteScalar("SELECT LAST_INSERT_ID();", transaction:=transaction)
                    If res > 0 Then 
transaction.Commit()
return true
end if
                    
                End Using
            End Using
于 2020-11-23T20:27:23.527 に答える
1

Dapper.Contrib.Extensions を簡単にする素晴らしいライブラリがあります。これを含めた後、次のように書くことができます:

public int Add(Transaction transaction)
{
        using (IDbConnection db = Connection)
        {
                return (int)db.Insert(transaction);
        }
}
于 2019-02-12T11:53:47.433 に答える
0

postgres 12.3で.netコア3.1を使用していました。Tadija Bagarić からの回答に基づいて、次のようになりました。

using (var connection = new NpgsqlConnection(AppConfig.CommentFilesConnection))
        {

            string insertUserSql = @"INSERT INTO mytable(comment_id,filename,content)
                    VALUES( @commentId, @filename, @content) returning id;";

            int newUserId = connection.QuerySingle<int>(
                                            insertUserSql,
                                            new
                                            {
                                                commentId = 1,
                                                filename = "foobar!",
                                                content = "content"
                                            }
                                            );

          


        }

AppConfig は、接続の詳細に設定された文字列を取得する独自のクラスです。これは、Startup.cs の ConfigureServices メソッド内で設定されます。

于 2021-02-06T09:59:32.937 に答える