2012-11-16 74 views
3

最近我发现实体框架不再满足将数据从一个数据库复制到另一个数据库的需求(它实在太慢了,而且我还想拉动更多数据比我一直)。于是我开始研究替代方案,并找到了SqlBulkCopy方法。问题是SqlBulkCopy不允许我“UPSERT”。再次,开始寻找解决方案,并遇到了DataTable.Merge(table)函数。实体框架的SqlBulkCopy(和更新)

根据我的研究,似乎“最佳做法”是使用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.从生产服务器提取所需的最小数据量并将其复制到本地数据库。

我目前的实现完全是基于实体框架的。它:

  1. 拉当天的一组数据从生产服务器
  2. 循环通过一组数据
  3. 将它与本地数据库
  4. 更新/根据需要增加

它正是我所需要的,但它超级慢(出于几个原因,我理解了所有这些)。因此,我希望更新它。

+0

为什么不使用像SSIS这样的ETL工具?这就是他们所设计的。 –

+0

@DStanley我无法使用SSIS,因为我正在使用SQL Server Express。 – 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) ; 

此外,如果需要再从表中卸下一切,你可以做到这一点通过使用TRUNCATEDelete from快得多。像这样:

TRUNCATE TABLE TableName; 
+0

我会喜欢,因为这是一个体面的解决方案,因为我不知道关于TRUNCATE的消息,但我更喜欢不使用直接SQL的解决方案。理想情况下,我想使用EF/ADO,但几乎没有真正的SQL。 – Kittoes0124

+2

@Kittoes为什么? EF它设计用于原子更新 - 而不是批量更新。如果你想要最高速度,你将不得不使用EF以外的东西。 –

+0

@DStanley这就是为什么我试图使用一个结合EF和ADO的解决方案。 EF生成查询逻辑和ADO来执行/插入/合并它。我只是无法真正保存更新。 – Kittoes0124