[C#] 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



답변

그것은 수행 지원 (를 포함하여 입력 / 출력 매개 변수를 RETURN사용하는 경우 값을) DynamicParameters하지만,이 경우 간단한 옵션은 간단하다 :

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

최신 버전의 SQL Server에서는 다음 OUTPUT절을 사용할 수 있습니다 .

var id = connection.QuerySingle<int>( @"
INSERT INTO [MyTable] ([Stuff])
OUTPUT INSERTED.Id
VALUES (@Stuff);", new { Stuff = mystuff});


답변

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


답변

여기에 늦은 대답 만은입니다 대안 받는 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가 삽입 된 객체를 반환합니다.

당신이 원하는 경우에 당신은 얻을 수 PhoneEmail또는 전체 삽입 된 행 :

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 테이블과 컬럼 참조가 중복되지 않도록 테이블 별명을 사용하여 삽입 및 삭제 된 트리거를 참조해야합니다.

문서에서 자세히 알아보기 : 링크


답변

SCOPE_IDENTITY가 10 진수 (38,0) 이기 때문에 InvalidCastException이 발생했습니다. 입니다.

다음과 같이 캐스팅하여 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();


답변

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


답변

인생을 더 편하게 만들어주는 훌륭한 도서관이 있습니다. Dapper.Contrib.Extensions. 이것을 포함하면 다음과 같이 쓸 수 있습니다.

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


답변

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));
        }
    }