2016-07-06 9 views
2

인 C# 트랜잭션 범위 나의 요구 사항은 백만 개의 레코드가있는 여러 비용 파일을 처리하는 것입니다. 처리 및 유효성 검사를 마친 후 해당 레코드를 데이터베이스에 추가해야합니다.수익률이

더 나은 성능을 위해 foreach 루프에서 "yield"을 사용하고 한 번에 하나의 레코드를 반환하고 해당 레코드를 처리 한 다음 해당 레코드 하나를 파일 번호가있는 데이터베이스에 즉시 추가하십시오. 이 파일을 읽는 동안 모든 데이터 유효성 검사 오류가 발생하면 InvalidRecordException이 발생합니다.

내 요구 사항은 해당 파일과 관련된 테이블에서 모든 레코드를 삭제하는 것입니다. 즉, 하나의 레코드가 유효하지 않더라도 해당 파일을 잘못된 파일로 표시하고 해당 파일의 레코드 하나를 데이터베이스에 추가하지 않겠습니다.

누구나 나를 도울 수 있습니다. 여기서 어떻게 TransactionScope를 사용할 수 있습니까?

public class CostFiles 
     { 
      public IEnumerable<string> FinancialRecords 
      { 
       get 
       { 
        //logic to get list of DataRecords 
        foreach (var dataRecord in DataRecords) 
        { 
         //some processing... which can throw InvalidRecord exception 
         yield return dataRecord;      
        } 
        yield break; 
       } 
      } 
     } 


     public void ProcessFileRecords(CostFiles costFile, int ImportFileNumber) 
     { 

      Database db = new Database(); 

      using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) 
      { 
       try 
       { 
        foreach (var record in costFile.FinancialRecords) 
        { 
         db.Add(record, ImportFileNumber); 

        } 
       } 
       catch(InvalidRecordException ex) 
       { 
        //here i want to delete all the records from the table where import file number is same as input paramter ImportFileNumber 
       } 
      } 
     } 
+1

'데이터베이스'란 무엇입니까? TransactionScope은 (일반적으로) 분산 트랜잭션 지원에 사용됩니다. 'Database'는 이것을 지원합니까? 네이티브 거래 개념을 사용할 수 있습니까? –

+2

데이터 작업을 처리하기 위해 저장 프로 시저를 사용하는 것이 좋습니다. 행을 고민하여이 행을 수행하는 것은 수백만 행으로 끔찍하게 느려질 것입니다. –

+0

@DavidOsborne'TransactionScope'는 "일반적으로 분산 트랜잭션 지원에 사용되지 않습니다." TransactionScope는 동일한 SQL 연결 개체를 다시 사용하지 않으면 트랜잭션을 분산 트랜잭션으로만 승격합니다. – DVK

답변

4

트랜잭션 범위의 목적은 "전체 또는 아무것도"시나리오를 작성하지 않으므로 전체 트랜잭션이 커밋되거나 전혀 커밋되지 않습니다. 적어도 TransactionScope의 관점에서 올바른 생각을 갖고있는 것 같습니다. TransactionScope.Complete()에 전화 할 때까지 범위가 실제로 데이터베이스에 커밋되지 않습니다. Complete()이 호출되지 않으면 레코드를 떠나면 레코드가 삭제됩니다. . 거래 범위를 쉽게 같은 것을 할 수있는 :

using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) 
{ 
    bool errorsEncountered = false; 

    try 
    { 
     foreach (var record in costFile.FinancialRecords) 
     { 
      db.Add(record, ImportFileNumber); 

     } 
    } 
    catch(InvalidRecordException ex) 
    { 
     //here i want to delete all the records from the table where import file number is same as input paramter ImportFileNumber 
     errorsEncountered = true; 
    } 

    if (!errorsEncountered) 
    { 
     scope.Complete(); 
    } 
} 

을 또는 당신은 추가가 예외를 던질 수 있도록하고 예외를 호출 할 수 없습니다를 Complete() 원인이됩니다, 대신 트랜잭션 범위의 외부로 처리하고 있습니다 따라서 추가 된 레코드가 없습니다.이 메서드는 추가 레코드의 처리를 중지 할 추가 이점이 있습니다. 이미 알았 으면 추가 레코드 처리가 중단됩니다.

try 
{ 
    using (var scope = new TransactionScope(TransactionScopeOptions.Required)) 
    { 
     foreach(var record in costFile.FinancialRecords) 
     { 
      db.Add(record, ImportFileNumber); 
     } 

     // if an exception is thrown during db.Add(), then Complete is never called 

     scope.Complete() 
    } 
    catch(Exception ex) 
    { 
     // handle your exception here 
    } 
} 

편집 당신이 당신의 트랜잭션 (추가 보안/네트워크 요구 사항이있을 수 있습니다) 분산 트랜잭션 (transaction)로 상승하지 않을 경우, 당신은 당신의 트랜잭션 범위 내에서 모든 데이터베이스 호출에 대해 동일한 SqlConnection 개체를 다시 사용할 수 있는지 확인하십시오.

using (var conn = new SqlConnection("myConnectionString")) 
{ 
    conn.Open(); 

    using (var scope = new TransactionScope(...)) 
    { 
     foreach(var foo in foos) 
     { 
      db.Add(foo, conn); 
     } 

     scope.Complete(); 
    } 
} 
+0

@ DVK : 설명해 주셔서 감사합니다. 예외의 경우 내가 처분 메소드를 호출하면 같은 importFileNumber를 가진 모든 레코드를 롤백 (삭제) 할 것인가? 또는 catch 블록에서 해당 importFileNumber 함께 데이터베이스에서 모든 레코드를 삭제합니다 저장된 프로 시저를 호출해야합니까? – bansi

+0

해당 가져 오기 파일 번호가있는 모든 레코드가 동일한 트랜잭션의 일부로 추가 된 경우 아무 것도 호출 할 필요가 없습니다. 레코드는'Complete()'가 호출 될 때까지 실제로 데이터베이스에 커밋되지 않으므로 complete를 호출하지 마십시오. 레코드 삭제는 범위 내에서 호출되면 트랜잭션의 일부로 간주되므로 'Complete()'가 호출 될 때까지 레코드는 삭제되지 않습니다. – DVK

+0

좋아 .. 알았어. 감사. – bansi