2012-11-16 2 views
3

최근에 Entity Framework가 한 데이터베이스에서 다른 데이터베이스로 데이터를 복사해야하는 필요성을 충족시키지 못했습니다. (너무 느리고 그 이상을 끌어 내고 싶습니다. 데이터보다). 그래서 대안을 찾기 시작했고 SqlBulkCopy 메소드를 발견했습니다. 문제는 SqlBulkCopy이 "UPSERT"를 허용하지 않는다는 것입니다. 다시 솔루션 찾기를 시작하여 DataTable.Merge(table) 함수를 발견했습니다.Entity Framework와의 SqlBulkCopy (및 Update)

제 연구에 따르면 SqlBulkCopy를 사용하여 데이터를 "준비 테이블"로 가져온 다음 DataTable.Merge()을 사용하고 변경 사항을 저장하는 것이 가장 좋은 방법 인 것 같습니다. 변경 사항을 저장하면 문제가 발생하는 부분입니다. 다음 코드가 있습니다 :

static void Main(string[] args) 
    { 
     using(var mdb = new meldbContext()) 
     using(var odb = new ocmgccazTestEnvDbContext()) 
     { 
      /*Is there a better way to clear the staging table that 
       doesn't require me to write actual SQL?*/ 
      odb.Database.ExecuteSqlCommand("DELETE FROM almCallDetail_staging"); 

      var lastUpdateTime = (from p in odb.almCallDetail 
            select p.time_of_contact).Max(); 

      var query = from p in mdb.cl_contact_event 
         where p.time_of_contact >= lastUpdateTime 
         select new almCallDetail 
         { 
          id = p.id, 
          contact_list_name = p.contact_list_name, 
          account_number = p.account_number, 
          time_of_contact = p.time_of_contact 
         }; 

      var conn = new SqlConnection(odb.Database.Connection.ConnectionString); 
      var bulkCopy = new SqlBulkCopy(conn) 
      { 
       BatchSize = 5000, 
       DestinationTableName = "almCallDetail_staging" 
      }; 

      conn.Open(); 
       bulkCopy.WriteToServer(query.ToDataTable());  

       var originalTable = (from p in odb.almCallDetail 
            where p.time_of_contact >= lastUpdateTime 
            select p).ToDataTable(); 

       var stagingTable = (from p in odb.almCallDetail_staging 
            select p).ToDataTable(); 

       /*Merge happens but the data is not actually saved to the almCallDetail 
        Table (originalTable)...*/ 
       originalTable.Merge(stagingTable); 
      conn.Close(); 
     } 
    } 

병합 작업 결과를 저장하려면 어떻게 변경합니까?

오히려 많은 양의 데이터를 신속하게 가져 오기/업데이트한다는 목표를 달성하기 위해 코드를 작성할 수있는 더 좋은 방법이 있습니까?

추가 설명 : 기본적으로 프로덕션 서버의 테이블에서 데이터를 복제하기 만하면 (나중에) 그룹에 대한 보고서로 바뀔 수있는 다양한 데이터 세트를 만들 수 있습니다. 데이터를 상대적으로 최신 상태로 유지하기 위해 매 30 분마다이 코드를 실행하는 예약 된 작업이 있으며 전체 프로세스가 가능한 한 효율적 이길 원합니다. I.E. 프로덕션 서버에 필요한 최소량의 데이터를 가져 와서 로컬 데이터베이스에 복사합니다.

현재 구현은 완전히 Entity Framework를 기반으로합니다. 그것은 :

  1. 업데이트/필요에 따라 추가 로컬 데이터베이스와 비교 데이터의 집합을 통해 프로덕션 서버에서
  2. 루프를 데이터의 현재 일의 세트를 가져옵니다

그것은 내가 필요로하는 것을 정확히한다. 그러나 그것은 매우 느리다 (몇 가지 이유로, 나는 모두 이해한다). 그러므로, 그것을 업데이트하려는 나의 소망.

+0

왜 SSIS와 같은 ETL 도구를 사용하지 않습니까? 그것이 그들이 설계 한 것입니다. –

+0

@DStanley SQL Server Express를 사용하고 있으므로 SSIS를 사용할 수 없습니다. – Kittoes0124

+0

이 문제에 대한 해결책을 찾아 냈습니까? –

답변

4

여기서 가장 빠른 방법은 (SSIS를 사용하지 않는 경우) MERGE 문과 함께 저장 프로 시저를 사용하는 것입니다.
저장 프로 시저에 연결된 서버를 추가하십시오. 이런 식으로 뭔가 작동합니다 : 당신이 다음 테이블 중 하나에서 모든 것을 제거해야하는 경우

또한
exec sp_addlinkedserver @server = 'ProductionServer' 

MERGE [LocalServer].dbName.dbo.TableName AS Target 
USING (SELECT * FROM [ProductionServer].dbName.dbo.TableName) AS source 
ON TARGET.Id = source.Id 
WHEN MATCHED 
THEN UPDATE 
SET Field1 = source.Field1, Field2 = source.Field2, ---etc.... 
WHEN NOT MATCHED BY TARGET THEN 
INSERT (Field1, Field2, Field3) 
VALUES (Field1, Field2, Field3) ; 

이, 당신이 할 수있는 훨씬 빠르게 Delete from보다 TRUNCATE를 사용하여. 이렇게 :

TRUNCATE TABLE TableName; 
+0

괜찮은 해결책이고 TRUNCATE에 관한 재미있는 일을 알지 못했기 때문에 upvote 할 것입니다.하지만 곧바로 SQL을 사용하지 않는 솔루션을 선호합니다. 이상적으로, 나는 실제 SQL을 거의 사용하지 않고 EF/ADO를 사용하고 싶습니다. – Kittoes0124

+2

@Kittoes 왜? EF는 일괄 업데이트가 아닌 원자 적 업데이트를 위해 설계되었습니다. 최고 속도를 원한다면 EF 이외의 것을 사용해야 할 것입니다. –

+0

@DStanley 그래서 EF와 ADO를 결합한 솔루션을 사용하려고합니다. EF를 사용하여 쿼리 로직과 ADO를 생성/삽입/병합합니다. 업데이트를 실제로 저장할 수 없었습니다. – Kittoes0124