LumenWorks (빠른 CSV 판독기)에서 여러 다른 파일 버전을 사용하는 동안 SqlBulkCopy를 사용하여 사용자 지정 클래스 w / IDataReader를 만드는 방법은 무엇입니까?

c# csv idatareader sqlbulkcopy

문제

메모리 문제로 인해 DataTable을 IDataReader로 대체 / 변환하기로 결정했습니다.

Google 및 MSDN 검색 중 꽤 많은 시간이 지나면 http://www.michaelbowersox.com/2011/12/22/using-a-custom-idatareader-to-stream-data-into-a-database 에서이 문제를 발견했습니다 . /Bulk Sql Server는 수백만 개의 레코드를 삽입 합니다.

LumenWorks Fast CSV Reader를 사용하고 있기 때문에 CsvReader에 IDataReader를 사용하여 두 가지 필드 버전을 사용하는 방법을 아직 알지 못했습니다. :-( csvReader.FieldCount는 여기 키이지만 CsvReader에 IDataReader 인터페이스를 갖는 두 개의 새로운 클래스 중 하나를 사용하는 방법을 설명하지 않습니다. 아래 원본 스크립트 및 수정 된 스크립트를 참조하십시오 ... 감사 ...

// 원본 스크립트 ...

var dbConnection = new SqlConnection(_dbConnectionString);

using (var dbBulkCopy = new SqlBulkCopy(dbConnection)
{
   using (CsvReader csvReader = new CsvReader(new StreamReader(filePath), false, '|', '"', '\\', '#', ValueTrimmingOptions.UnquoteOnly))
   {
       while(csvReader.ReadNextRecord())
       {
           if (csvReader.FieldCount == 48)
           {
               //Version 1...
               dataRow["DealerId"] = csvReader[0];
               dataRow["DealerName"] = csvReader[1];
               //Etc...
           }
           else if (csvReader.FieldCount == 51)
           {
               //Version 2...
               dataRow["DealerId"] = csvReader[0];
               dataRow["DealerName"] = csvReader[1];
               //Etc...
           }
           else { throw new Exception("Field Total Count Mismatched"); }

           dataTable.Rows.Add(dataRow);
       }

       dbConnection.Open();

       dbBulkCopy.WriteToServer(dataTable);
   }
}

// 새 스크립트 ...

 var dbConnection = new SqlConnection(_dbConnectionString);

using (var dbBulkCopy = new SqlBulkCopy(dbConnection)
{
   dbConnection.Open();

   using (CsvReader csvReader = new CsvReader(new StreamReader(filePath), false, '|', '"', '\\', '#', ValueTrimmingOptions.UnquoteOnly))
   {
       csvReader.ReadNextRecord();

       dbBulkCopy.WriteToServer(
           if (csvReader.FieldCount == 48)
           {
               //Version 1...

               csvReader....???  //Assign a custom class having IDataTable...
           }
           else if (csvReader.FieldCount == 51)
           {
               //Version 2...
               csvReader....???  //Assign a custom class having IDataTable...
           }
           else { throw new Exception("Field Total Count Mismatched"); }
        );
   }
}

// 샘플 스크립트 ...

using (var file = new StreamReader(path))
using (var csv = new CsvReader(file, true)) // true = has header row
using (var bcp = new SqlBulkCopy(connection)) {
    bcp.DestinationTableName = "TableName";
    bcp.WriteToServer(csv);
}

인기 답변

이후로는 조금 길어질 것입니다. 답으로 쓰고 있습니다.

* 나는 다른 필드 명령과 함께 오는 두 종류의 CSV 파일을 갖고 있음에도 불구하고 목표 테이블이 동일 하다고 가정하고 있습니다. * [편집] 귀하의 의견에 명시 할 필요는 없습니다.

컨텍스트를 이해할 수 있도록 여기 에서 샘플 데이터를 얻었 습니다.

첫 번째 파일 유형이 다음과 같다고 가정 해 보겠습니다.

Rk,Year,Age,Tm,Lg,Id,G,W,L,W-L,Finish,
1,1978,37,Atlanta Braves,NL,,162,69,93,.426,6

그리고 두 번째 유형은 (일부 컬럼은 Age <-> Finish로 바뀌고 추가 필드가 있습니다)

Rk,Year,Finish,Tm,Lg,Id,G,W,L,W-L,Age,Test1,Test2,Test3
1,1978,Very good year,Atlanta Braves,NL,,162,69,93,.426,96,,,,

따라서 목표 테이블은 (열만)

Rk,Year,Finish,Tm,Lg,Id,G,W,L,W-L,Age,Test1,Test2,Test3

여기에 두 가지 옵션이 있습니다 (끝에 +1 옵션이 있음) .

옵션 1

  1. 단계 0을 추가하여 필드 형식을 정의하여 필드 수준에서 모든 입력 파일을 동일하게 만듭니다. 이것은 데이터베이스에있는 것과 동일한 필드를 작성하여 수행 할 수 있습니다.

[Test4와 Test5가 대상 테이블에 있지만 두 CSV 파일 모두에없는 열이라고 상상해 봅시다.]

Rk,Year,Finish,Tm,Lg,Id,G,W,L,W-L,Age,Test1,Test2,Test3,Test4,Test5
  1. 가지고있는 모든 파일을 구문 분석하여 정의한 형식을 존중하는 파일 하나 (또는 ​​여러 파일)에 파일을 다시 작성하십시오. 이렇게하면 고유 한 형식의 파일이 1 개 (또는 여러 개) 있습니다.

  2. 이 파일을 구문 분석하여 csv reader를 사용하여 데이터베이스에 삽입 할 수 있습니다. 필드 비 호환성 문제는 고유 한 형식으로 얻은 마지막 파일로 처리되기 때문입니다.

옵션 2

SqlBulkCopy 작업을 두 번 수행합니다. 첫 번째 라운드에서는 48 개의 필드가있는 파일을 읽고 다음 라운드에서는 51 개의 필드가있는 파일을 읽습니다.

            var FilesWith48Fields = Directory.GetFiles(@"D:\Data\48Fields", "*.csv");

            foreach (var fileName in FilesWith48Fields)
            {
                using (var file = new StreamReader(fileName))
                using (var csv = new CsvReader(file, true)) // true = has header row
                using (var bcp = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepNulls))
                {
                    bcp.DestinationTableName = "fletchsodTable";
                    // map the first field of your CSV to the column in Database
                    var mapping1 = new SqlBulkCopyColumnMapping(0, "FirstColumnName");
                    bcp.ColumnMappings.Add(mapping1);

                    var mapping2 = new SqlBulkCopyColumnMapping(1, "SecondColumnName");
                    bcp.ColumnMappings.Add(mapping2);  
                    ....

                    bcp.WriteToServer(csv);
                }
            }

그리고 51 개의 필드를 가진 파일에서도 똑같이 반복하십시오.

var FilesWith51Fields = Directory.GetFiles(@"D:\Data\51Fields", "*.csv");
......

SqlBulkCopyColumnMapping에 대한 자세한 내용은 여기를 참조하십시오 .

옵션 3

데이터 리더를 만드는 모험을 원할 경우 다음 링크를 참조하십시오.

Daniel Wertheim의 블로그

codeproject에 대한 샘플 암시

다른 것

그리고 마침내 MSDN

개인 메모 시간 부족으로 인해 비슷한 문제가 발생했습니다. 3 단위 옵션을 포기했습니다. 단위 테스트 및 최적화가 필요하고 또 다른 조정이 필요하기 때문에 시간이 걸릴 수 있습니다. ( 적어도 제게는 케이스 )

OPTION 4 아마도 OPTION 2에서 가리킨 열 매핑을 사용하면 필드 수를 테스트하여 길을 구현할 수 있습니다. 그러나 본능적으로, 나는 하드 코딩 된 정수로 필드를 계산하지 않는 것이 좋습니다.



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.