dapper.net에서 트랜잭션을 사용하는 방법은 무엇입니까?


106

여러 테이블에서 여러 삽입 문을 실행하고 싶습니다. dapper.net을 사용하고 있습니다. dapper.net으로 트랜잭션을 처리 할 방법이 없습니다.

dapper.net에서 거래를 사용하는 방법에 대한 아이디어를 공유하십시오.

답변:


107

다음은 코드 스 니펫입니다.

using System.Transactions;    
....    
using (var transactionScope = new TransactionScope())
{
    DoYourDapperWork();
    transactionScope.Complete();
}

System.Transactions기본적으로 참조되지 않으므로 어셈블리 에 대한 참조를 추가해야합니다 .


7
오류시 명시 적으로 롤백해야합니까? 아니면 System.Transactions가이를 자동으로 처리합니까?
노르 베르트 Norbertson

6
@NorbertNorbertson은 Dispose()방법 으로 자동으로 수행합니다 . Complete()호출되지 않은 경우 트랜잭션이 롤백됩니다.
the_joric

4
다른 답변 ( stackoverflow.com/a/20047975/47672 ) 때문에 언급 할 가치가 TransctionScope있습니다.이 답변을 선택하는 경우 사용 블록 내부에서 연결을 열어야합니다 .
0x49D1

2
참조 ( stackoverflow.com/a/20047975/444469)-DoYouDapperWork (실행, 쿼리 등 ...)는 매개 변수에 트랜잭션이 필요합니다.
Matthieu

문제가있는 경우 롤백이 자동으로 호출됩니까?
gandalf

91

연결에서 직접 트랜잭션을 가져 오는 방식으로보다 직관적 인 접근 방식을 선호했습니다.

// This called method will get a connection, and open it if it's not yet open.
using (var connection = GetOpenConnection())
using (var transaction = connection.BeginTransaction())
{
    connection.Execute(
        "INSERT INTO data(Foo, Bar) values (@Foo, @Bar);", listOf5000Items, transaction);
    transaction.Commit();
}

@ANeves : 글쎄, 우리는 아마도 다른 Dapper 프레임 워크를 사용하고있을 것입니다. github.com/StackExchange/dapper-dot-net
andrecarlucci 2014

25
.begintransaction 전에 connection.open ()을 호출해야합니다.
Timeless

트랜잭션 범위 내에서 연결을 열지 않는 한 연결은 트랜잭션 범위에 자동으로 등록되지 않습니다. 나는 GetOpenConnection 어떻게 든 마술 TransactionScope에 내 자신을 열 경우 코드가 어떻게 작동하는지 모르겠지만, 그렇지 않은 것을 내기 거라고
에릭 Bergstedt

@ErikBergstedt, 우리가 호출 한 후에 만 연결 열어야 한다는 말입니까? 이 경우이 확장 방법은 트랜잭션의 잘못된 사용을 촉진합니다. (IMO, "연결이 이미 열린 후 트랜잭션을 열 수 없습니다"를 던질 수도 있습니다.).BeginTransaction()
ANeves

2
Execute필수 항목이므로 에서 매개 변수로 트랜잭션을 포함하는 것이 좋습니다.
Arve Systad 2017-06-14

19

TransactionScopeDapper는 ADO.NET 명령 만 실행하므로 사용할 수 있어야 합니다.

using (var scope = new TransactionScope())
{
   // insert
   // insert
   scope.Complete();
}

8

모든 테이블이 단일 데이터베이스에 있다는 것을 고려할 때 TransactionScope여기에 몇 가지 답변에 제안 된 솔루션에 동의하지 않습니다 . 답변을 참조하십시오 .

  1. TransactionScope일반적으로 분산 트랜잭션에 사용됩니다. 서로 다른 데이터베이스에 걸친 트랜잭션은 서로 다른 시스템에있을 수 있습니다. 이를 위해서는 운영 체제 및 SQL Server에서 일부 구성이 필요합니다. 그렇지 않으면 작동하지 않습니다. 모든 쿼리가 단일 데이터베이스 인스턴스에 대한 경우에는 권장되지 않습니다.
    그러나 단일 데이터베이스를 사용하면 제어 할 수없는 트랜잭션에 코드를 포함해야 할 때 유용 할 수 있습니다. 단일 데이터베이스를 사용하면 특별한 구성도 필요하지 않습니다.

  2. connection.BeginTransaction단일 데이터베이스에 대해 트랜잭션 (C #, VB.NET 등)을 구현하는 ADO.NET 구문입니다. 이것은 여러 데이터베이스에서 작동하지 않습니다.

그래서 connection.BeginTransaction()더 나은 방법입니다.

트랜잭션을 처리하는 더 좋은 방법은 답변 에서 설명한대로 UnitOfWork를 구현 하는 것입니다.


4
하나는 TransactionScope의 이점을 얻기 위해 여러 데이터베이스가 필요하지 않습니다. 특히 유용성은 주변 환경이라는 것입니다. 소유하지 않거나 수정할 수없는 코드를 트랜잭션에서 래핑하는 데 유용합니다. 예를 들어, 데이터베이스 호출을 수행하는 단위 / 통합 테스트 코드에서 롤백하려는 위치에 큰 효과를 낼 수 있습니다. TransactionScope를 플로팅하고 코드를 테스트 한 다음 테스트 정리 중에 폐기하면됩니다.
Larry Smith

3
@LarrySmith : 동의합니다. 그러나 질문은 이것에 관한 것이 아닙니다. OP는 하나의 트랜잭션에서 여러 테이블에 삽입하고 싶다고 말합니다. 받아 들인 답변을 포함한 일부 답변 TransactionScope은 OP가 원하는 것에 대해 비효율적 인 사용 을 제안합니다 . 나는 그것이 TransactionScope많은 경우에 좋은 도구 라는 데 동의합니다 . 그러나 이것은 아닙니다.
Amit Joshi

5

Daniel의 대답은 예상대로 작동했습니다. 완전성을 위해 트랜잭션 범위와 dapper를 사용하여 커밋 및 롤백을 보여주는 스 니펫은 다음과 같습니다.

using System.Transactions;
    // _sqlConnection has been opened elsewhere in preceeding code 
    using (var transactionScope = new TransactionScope())
    {
        try
        {
            long result = _sqlConnection.ExecuteScalar<long>(sqlString, new {Param1 = 1, Param2 = "string"});

            transactionScope.Complete();
        }
        catch (Exception exception)
        {
            // Logger initialized elsewhere in code
            _logger.Error(exception, $"Error encountered whilst executing  SQL: {sqlString}, Message: {exception.Message}")

            // re-throw to let the caller know
            throw;
        }
    } // This is where Dispose is called 

2
@usr은 개인 취향에 따라 결정됩니다. 나는 처음에 무언가 잘못되었을 때를 알고 싶고 로그 진술을 쓰레기로 보지 않는 것을 선호합니다. 또한, 날씬한와 함께 사용하기 거래하는 한 가지 방법을 설명하여 내 대답은 여전히 광고 값
Sudhanshu 슈라을

@CodeNaked, 먼저 주문이 잘못되었습니다. 예외가 있으면 catch 블록이 먼저 히트 한 다음 사용 범위가 끝납니다. 둘째,이 답변과 참조 된 MSDN 문서를 살펴보십시오. stackoverflow.com/a/5306896/190476 dispose를 두 번 호출하는 것은 해롭지 않으며 잘 설계된 개체는 두 번째 호출을 무시합니다. 반대표는 정당화되지 않습니다!
Sudhanshu Mishra

@dotnetguy- Dispose첫 번째 또는 두 번째로 호출 되는 메서드 를 전달하려고 시도한 것이 아니라 두 번 호출되었습니다. "처분을 두 번 호출하는 것이 해롭지 않다"는 점에 관해서는 그것은 큰 가정입니다. 문서와 실제 구현이 종종 일치하지 않는다는 것을 배웠습니다. 하지만 마이크로 소프트의 말을 원한다면 : msdn.microsoft.com/en-us/library/…
CodeNaked

3
그래서, 코드 분석 경고가 당신의 반대 투표 이유입니까? 그렇다고 답이 틀리거나 오해의 소지가있는 것은 아닙니다. 그 때 반대표가 적절합니다. 기능을 유지하면서 답을 편집하고 더 나은 솔루션을 제안하지 않겠습니까? 스택 오버플로는 도움과 건설적인 비판에 관한 것입니다.
Sudhanshu Mishra
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.