2013-03-18 22 views
8

アプリケーションを実行するときに挿入する必要がある2つのテーブルがあります。
のはSqlBulkCopy複数のテーブル単一のトランザクションでの挿入またはEntity FrameworkとClassic間の一括挿入操作Ado.net

  • tbl_FirstTableとtbl_SecondTable

私の問題は、データ量であるが以下のように、私はテーブルがあるとしましょう。
tbl_FirstTableに10,000行以上、tbl_SecondTableに500,000行以上を挿入する必要があります。

したがって、私は以下のようにエンティティフレームワークを使用します。

public bool Save_tbl_FirstTable_Vs_tbl_SecondTable(List<tbl_FirstTable> List_tbl_FirstTable, List<tbl_SecondTable> List_tbl_SecondTable) 
{ 
    bool IsSuccessSave = false; 
    try 
    { 
     using (DummyDBClass_ObjectContext _DummyDBClass_ObjectContext = new DummyDBClass_ObjectContext()) 
     {   
      foreach (tbl_FirstTable _tbl_FirstTable in List_tbl_FirstTable) 
      { 
       _DummyDBClass_ObjectContext.tbl_FirstTable.InsertOnSubmit(_tbl_FirstTable); 
      } 

      foreach (tbl_SecondTable _tbl_SecondTable in List_tbl_SecondTable) 
      { 
       _DummyDBClass_ObjectContext.tbl_SecondTable.InsertOnSubmit(_tbl_SecondTable); 
      } 

      _DummyDBClass_ObjectContext.SubmitChanges(); 
      IsSuccessSave = true; 
     } 
    } 
    catch (Exception ex) 
    { 
     Log4NetWrapper.WriteError(string.Format("{0} : {1} : Exception={2}", 
            this.GetType().FullName, 
            (new StackTrace(new StackFrame(0))).GetFrame(0).GetMethod().Name.ToString(), 
            ex.Message.ToString())); 

     if (ex.InnerException != null) 
     { 
      Log4NetWrapper.WriteError(string.Format("{0} : {1} : InnerException Exception={2}", 
            this.GetType().FullName, 
            (new StackTrace(new StackFrame(0))).GetFrame(0).GetMethod().Name.ToString(), 
            ex.InnerException.Message.ToString())); 
     } 
    } 

    return IsSuccessSave; 
} 

これは、エラーTime out exceptionに直面している場所です。
以下のコードを使用すると例外が解決すると思います。

DummyDBClass_ObjectContext.CommandTimeout = 1800; // 30 minutes 

私はそれを使用しました。解決しましたが、別のエラーOutOfMemory Exceptionに直面します。
私は解決策を探しましたが、幸いにも、私は以下の記事を見つけました。

  1. Problem with Bulk insert using Entity Framework
  2. Using Transactions with SqlBulkCopy
  3. Performing a Bulk Copy Operation in a Transaction

その記事によると、私はクラシックADO.netコードにEntity Frameworkのから私のコードを変更します。

public bool Save_tbl_FirstTable_Vs_tbl_SecondTable(DataTable DT_tbl_FirstTable, DataTable DT_tbl_SecondTable) 
{ 
    bool IsSuccessSave = false; 
    SqlTransaction transaction = null; 
    try 
    { 
     using (DummyDBClass_ObjectContext _DummyDBClass_ObjectContext = new DummyDBClass_ObjectContext()) 
     { 
      var connectionString = ((EntityConnection)_DummyDBClass_ObjectContext.Connection).StoreConnection.ConnectionString; 
      using (SqlConnection connection = new SqlConnection(connectionString)) 
      { 
       connection.Open(); 
       using (transaction = connection.BeginTransaction()) 
       { 
        using (SqlBulkCopy bulkCopy_tbl_FirstTable = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))        
        { 
         bulkCopy_tbl_FirstTable.BatchSize = 5000; 
         bulkCopy_tbl_FirstTable.DestinationTableName = "dbo.tbl_FirstTable"; 
         bulkCopy_tbl_FirstTable.ColumnMappings.Add("ID", "ID"); 
         bulkCopy_tbl_FirstTable.ColumnMappings.Add("UploadFileID", "UploadFileID"); 
         bulkCopy_tbl_FirstTable.ColumnMappings.Add("Active", "Active"); 
         bulkCopy_tbl_FirstTable.ColumnMappings.Add("CreatedUserID", "CreatedUserID"); 
         bulkCopy_tbl_FirstTable.ColumnMappings.Add("CreatedDate", "CreatedDate"); 
         bulkCopy_tbl_FirstTable.ColumnMappings.Add("UpdatedUserID", "UpdatedUserID"); 
         bulkCopy_tbl_FirstTable.ColumnMappings.Add("UpdatedDate", "UpdatedDate"); 
         bulkCopy_tbl_FirstTable.WriteToServer(DT_tbl_FirstTable); 
        } 

        using (SqlBulkCopy bulkCopy_tbl_SecondTable = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))        
        { 

         bulkCopy_tbl_SecondTable.BatchSize = 5000; 
         bulkCopy_tbl_SecondTable.DestinationTableName = "dbo.tbl_SecondTable"; 
         bulkCopy_tbl_SecondTable.ColumnMappings.Add("ID", "ID"); 
         bulkCopy_tbl_SecondTable.ColumnMappings.Add("UploadFileDetailID", "UploadFileDetailID"); 
         bulkCopy_tbl_SecondTable.ColumnMappings.Add("CompaignFieldMasterID", "CompaignFieldMasterID"); 
         bulkCopy_tbl_SecondTable.ColumnMappings.Add("Value", "Value"); 
         bulkCopy_tbl_SecondTable.ColumnMappings.Add("Active", "Active"); 
         bulkCopy_tbl_SecondTable.ColumnMappings.Add("CreatedUserID", "CreatedUserID"); 
         bulkCopy_tbl_SecondTable.ColumnMappings.Add("CreatedDate", "CreatedDate"); 
         bulkCopy_tbl_SecondTable.ColumnMappings.Add("UpdatedUserID", "UpdatedUserID"); 
         bulkCopy_tbl_SecondTable.ColumnMappings.Add("UpdatedDate", "UpdatedDate"); 
         bulkCopy_tbl_SecondTable.WriteToServer(DT_tbl_SecondTable); 
        } 


        transaction.Commit(); 
        IsSuccessSave = true; 
       } 
       connection.Close(); 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     if (transaction != null) 
      transaction.Rollback(); 

     Log4NetWrapper.WriteError(string.Format("{0} : {1} : Exception={2}", 
            this.GetType().FullName, 
            (new StackTrace(new StackFrame(0))).GetFrame(0).GetMethod().Name.ToString(), 
            ex.Message.ToString())); 

     if (ex.InnerException != null) 
     { 
      Log4NetWrapper.WriteError(string.Format("{0} : {1} : InnerException Exception={2}", 
            this.GetType().FullName, 
            (new StackTrace(new StackFrame(0))).GetFrame(0).GetMethod().Name.ToString(), 
            ex.InnerException.Message.ToString())); 
     } 
    } 

    return IsSuccessSave; 
} 

最後に、500,000を超える行に対して15秒未満で挿入処理を実行します。

このシナリオを投稿する理由は2つあります。

  1. 私が知ったことを分かち合いたいと思います。
  2. 私は完璧ではないので、私はまだあなたからより多くの提案を得る必要があります。

だから、すべてのよりよい解決策が理解されるであろう。

+0

なぜあなたは心配していますか? – TalentTuner

答えて

0

すべての挿入の前にContext.ConfigurationでAutoDetectChangesEnabled = falseを設定してみましたか?

+0

はい、確かに、私はそれをしました。しかし、Exceptionには 'Configuration'の定義がなく、 'Configuration'という拡張メソッドもないことがわかりました。 'System.Data.Objects.ObjectContext'を使用しました –

+0

私が試した最初の方法は、そのリンクhttp://stackoverflow.com/a/5942176/900284に従って' AutoDetectChangesEnable = False'です。しかし、なぜ私は 'Context.Configuration'を使うことができないのかまだ分かりません。 –

+0

遅れて申し訳ありません。コンテキストは、ユーザーが定義し、System.Data.Entity.DbContextから継承して、ObjectContextではなくそのプロパティを使用する必要があります。 EF 5を使用している場合は、EF Designerが生成すると聞きました。 DbContextで "using"を使用し続けると、短命に保たれます。 – Thabo

0

1)ここでEF5.x

よりもはるかに優れた性能を持って使用EF6.xは、Bulk insert with EFからより多くの提案()

2)があるため、新たなコンテキストを使用して、グラフの小型アクティブコンテキストをキープ各作業ユニット

3)AutoDetechChangesEnabled - context.Configurationをオフにします。AutoDetectChangesEnabled = false;

4)定期的にSaveChangesを呼び出してバッチ処理する

関連する問題