2013-03-18 7 views
8

Mam dwie tabele, które należy wstawić, gdy moja aplikacja uruchomiona.
Powiedzmy, że mam tabele następnieSqlBulkCopy Wiele tabel Wstaw w ramach pojedynczej transakcji LUB operacji wsadowej wstawiania między Entity Framework i Classic Ado.net

  • tbl_FirstTable i tbl_SecondTable

mój problem jest ilość danych.
Potrzebuję wstawić ponad 10 000 wierszy do tbl_FirstTable i ponad 500 000 wierszy do tbl_SecondTable.

Fristly, używam framework podmiotu w następujący sposób.

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

To jest miejsce, w którym wystąpił błąd Time out exception.
Myślę, że ten wyjątek zostanie rozwiązany, jeśli użyję poniższego kodu.

DummyDBClass_ObjectContext.CommandTimeout = 1800; // 30 minutes 

Więc go użyłem. Rozwiązanie zostało rozwiązane, ale mam inny błąd: OutOfMemory Exception.
Więc szukałem rozwiązań, na szczęście znalazłem poniżej artykuły.

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

Według że artykuły, mogę zmienić kod z Entity Framework do kodu Klasyczny ADO.NET.

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

Wreszcie wykonuje proces wstawiania w mniej niż 15 sekund dla ponad 500 000 wierszy.

Istnieją dwa powody, dla których zamieszczam ten scenariusz.

  1. Chciałbym podzielić się tym, co dowiedziałem się.
  2. Ponieważ nie jestem doskonały, wciąż potrzebuję więcej sugestii od ciebie.

Więc każde lepsze rozwiązanie zostanie docenione.

+0

dlaczego i czego się martwisz? – TalentTuner

Odpowiedz

0

Czy próbowałeś ustawić AutoDetectChangesEnabled = false w Context.Configuration przed wszystkimi wstawkami?

+0

Tak, na pewno, zrobiłem to. Ale znalazłem wyjątek 'nie zawiera definicji" Konfiguracja "i nie ma metody rozszerzenia" Konfiguracja ". Użyłem 'System.Data.Objects.ObjectContext' –

+0

Pierwszym sposobem, jaki wypróbowałem, jest' AutoDetectChangesEnable = False' zgodnie z tym linkiem http://stackoverflow.com/a/5942176/900284. Ale nadal nie wiem, dlaczego nie mogę użyć "Context.Configuration". –

+0

Przepraszamy za opóźnioną odpowiedź. Twój kontekst powinien zostać zdefiniowany przez Ciebie i dziedziczyć po System.Data.Entity.DbContext, aby użyć tej właściwości, a nie ObjectContext. Jeśli używasz EF 5, słyszę, że EF Designer nawet je generuje. Kontynuuj używanie "using" w DbContext, aby zachować krótkość. – Thabo

0

1) Wykorzystanie EF6.x, który ma znacznie lepszą wydajność niż EF5.x

Oto kolejne propozycje (od Bulk insert with EF)

2) prowadzenia aktywnym kontekście wykresu mały stosując nowy kontekst każdy Unit of Work

3) Wyłącz AutoDetechChangesEnabled - context.Configuration.AutoDetectChangesEnabled = false;

4) Wiązanie, w pętli, Dzwoń pod SaveChanges okresowo

Powiązane problemy