2011-02-17 104 views
1

我正在将数据库从MS Access移到sql server。为了将数据移动到新表中,我决定编写一个同步例程,因为模式已经发生了很大的变化,它使我能够对运行它的程序运行测试,并在需要新的测试数据时重新同步。然后最终我会做最后一次同步并开始在新的sql服务器版本上生效。SqlBulkCopy计算字段

不幸的是我遇到了阻碍,我的方法是下面复制从Access到SQLServer的

public static void BulkCopyAccessToSQLServer 
     (string sql, CommandType commandType, DBConnection sqlServerConnection, 
      string destinationTable, DBConnection accessConnection, int timeout) 
    { 
     using (DataTable dt = new DataTable()) 
     using (OleDbConnection conn = new OleDbConnection(GetConnection(accessConnection))) 
     using (OleDbCommand cmd = new OleDbCommand(sql, conn)) 
     using (OleDbDataAdapter adapter = new OleDbDataAdapter(cmd)) 
     { 
      cmd.CommandType = commandType; 
      cmd.Connection.Open(); 
      adapter.SelectCommand.CommandTimeout = timeout; 
      adapter.Fill(dt); 

      using (SqlConnection conn2 = new SqlConnection(GetConnection(sqlServerConnection))) 
      using (SqlBulkCopy copy = new SqlBulkCopy(conn2)) 
      { 
       conn2.Open(); 

       copy.DestinationTableName = destinationTable; 
       copy.BatchSize = 1000; 
       copy.BulkCopyTimeout = timeout; 
       copy.WriteToServer(dt); 
       copy.NotifyAfter = 1000; 
      } 
     } 
    } 

基本上这个查询使用输入SQL字符串这所有正确的字段名,所以我不要了数据访问不需要设置列映射。

这是工作,直到我到达一个计算字段的表。 SQLBulkCopy似乎并不知道要跳过该字段并尝试更新失败的列,但出现错误“列'columnName'不能被修改,因为它既可以是计算列,也可以是联合运算符的结果。”

是否有一种简单的方法可以使其跳过计算的字段?

我希望不必指定一个完整的列映射。

回答

5

有两种方法来躲过此:

  • 使用ColumnMappings正式定义列关系(你注意到你不想要这个)
  • 推数据到临时表 - 一个基本的表,不是你的核心事务表的一部分,它的全部目的是像一样像这样的数据导入;然后用T-SQL命令来将数据从临时表中转移到真正的表

我总是青睐有第二种选择,因为各种原因:

  • 我从来没有与映射混乱 - 这是对我来说其实很重要,p
  • 插入到真正的表将被完全记录(SqlBulkCopy一定登录)
  • 我必须以最快的速度插入 - 没有约束检查,没有索引,等等
  • 我不会在导入过程中绑定事务表,并且不存在针对部分导入的表运行不可重复查询的风险
  • 如果导入失败中途没有,我有一个安全中止选项必须使用事务处理(此时什么都没有触及事务系统)
  • 它将数据处理推入实际表时可以进行某种级别的数据处理,而不需要在应用层缓冲DataTable中的所有内容,或者实现自定义IDataReader
+1

而不是一个临时表,我会建议一个可更新的视图,只包括colu没有计算的mns,然后批量复制到视图中。 – 2016-04-23 15:01:08