web-dev-qa-db-ja.com

Dapperで挿入を実行し、挿入されたIDを返すにはどうすればよいですか?

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

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

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
159
ppiotrowicz

RETURNを使用するとsupport入出力パラメーター(DynamicParameters値を含む)を実行しますが、この場合の単純なオプションは単純です:

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

var id = connection.Query<int>(sql, new { Stuff = mystuff}).Single();
258
Marc Gravell

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();
47
jww

遅い回答ですが、ここに使用したSCOPE_IDENTITY()回答に対する代替があります: OUTPUT INSERTED

挿入されたオブジェクトの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);

また、これにより、deletedまたはupdated行のデータを返すことができます。次の理由でトリガーを使用している場合は注意してください。

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

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

詳細については、ドキュメントをご覧ください: link

32
Tadija Bagarić

取得している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();
5
bpruitt-goddard

私がSQL 2000に反対しているからかどうかはわかりませんが、SQLを機能させるにはこれをしなければなりませんでした。

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();
4
mytydev

Dapper.SimpleSaveを使用している場合:

 //no safety checks
 public static int Create<T>(object param)
    {
        using (SqlConnection conn = new SqlConnection(GetConnectionString()))
        {
            conn.Open();
            conn.Create<T>((T)param);
            return (int) (((T)param).GetType().GetProperties().Where(
                    x => x.CustomAttributes.Where(
                        y=>y.AttributeType.GetType() == typeof(Dapper.SimpleSave.PrimaryKeyAttribute).GetType()).Count()==1).First().GetValue(param));
        }
    }
0
Lodlaiden

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

public int Add(Transaction transaction)
{
        using (IDbConnection db = Connection)
        {
                return (int)db.Insert(transaction);
        }
}
0
Wings