SqlBulkCopy使用注意事項


1. 有標識列的表

1.1 SqlBulkCopyOptions.KeepIdentity  必須設置!否則會出現復制過去的數據產生標識列發現變化的情況!

1.2 如果原表的標識列即為主鍵, 那按1.1 的設置已足夠。 如果原表無主鍵, 那在復制之前必須先清空原表(truncate table), 否則會出現多個相同的標識值的列!

2. 為NULL值的列

2.1 SqlBulkCopyOptions.KeepNulls 必須設置!否則會出現源數據的字段為NULL時, 復制過去卻成了默認值!

 

其它幾個選項的說明與分析:

 Default  對所有選項使用默認值。  
 KeepIdentity 保留源標識值。如果未指定,則由目標分配標識值。  
 CheckConstraints  請在插入數據的同時檢查約束。默認情況下,不檢查約束。  
 TableLock  在批量復制操作期間獲取批量更新鎖。如果未指定,則使用行鎖。  
 KeepNulls 保留目標表中的空值,而不管默認值的設置如何。如果未指定,則空值將由默認值替換(如果適用)。  
 FireTriggers  指定后,會導致服務器為插入到數據庫中的行激發插入觸發器。  默認情況下, 是不激發觸發器的……
 UseInternalTransaction  如果已指定,則每一批批量復制操作將在事務中發生。 在一個事務中執行,要么都成功,要么都不成功

 

Default 就沒有什么好說的了, 不要

KeepIdentity  和 KeepNulls  上面已有了, 不再分析。

CheckConstraints 不需要, 因為是現成的數據, 既然已在DB中, 必然是通過了約束檢查的。

TableLock 不需要, 因為復制時兩個庫都需要處於單連接狀態, 不可能有干擾。

FireTriggers  一般就不需要了吧, 畢竟只是復制數據, 而且是現成的數據……

UseInternalTransaction  關系也不大, 反正復制失敗會記錄到自定義的日志, 失敗了也知道, 重來一次就可以了。

 

下面是便於測試的代碼

SQL:

--1. 建數據來源表
IF EXISTS (  
       SELECT 1 FROM   sysobjects  
       WHERE  id = OBJECT_ID(N'Table_1')  
              AND OBJECTPROPERTY(id, N'IsUserTable') = 1  
   )  
BEGIN  
    DROP TABLE Table_1  
END  
GO  
Create Table Table_1(    
    ID INT, 
    [NAME] VARCHAR(50) DEFAULT('xx')
)
GO
INSERT INTO Table_1
SELECT 1,'a' UNION
SELECT 2,'b' UNION
SELECT 3,'c' UNION
SELECT 4,'d' UNION
SELECT 5,'e' UNION
SELECT 6,null
 
--2. 建目標表
IF EXISTS (  
       SELECT 1 FROM   sysobjects  
       WHERE  id = OBJECT_ID(N'Table_2')  
              AND OBJECTPROPERTY(id, N'IsUserTable') = 1  
   )  
BEGIN  
    DROP TABLE Table_2  
END  
GO  
Create Table Table_2(    
    ID2 INT, 
    [NAME2] VARCHAR(50) DEFAULT('xx')
)
GO
 
 
--復制時的對應關系
--Tabe_1 ==> Table_2
--ID     ==> ID2
--[NAME] ==> [NAME2]

 

C# 控制台程序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Collections;
 
namespace SqlBulkCopyDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            string connString = System.Configuration.ConfigurationManager.AppSettings["DCString"];
            SqlConnection ConnectionNew = new SqlConnection(connString);
            SqlConnection ConnectionOld = new SqlConnection(connString);
            bool ExportInfo = System.Configuration.ConfigurationManager.AppSettings["ExportInfo"].ToLower()=="true";
            try
            {
                ConnectionNew.Open();
                ConnectionOld.Open();
 
                //1.在舊表中,用SqlDataReader讀取出信息  
                string SQL = "select * from Table_1";
 
                SqlCommand cmd = new SqlCommand(SQL, ConnectionOld);
                cmd.CommandTimeout = 7200;
                SqlDataReader sdr = cmd.ExecuteReader();
 
                //2.初始化SqlBulkCopy對象,用新的連接作為參數。  
                SqlBulkCopy bulkCopy = new SqlBulkCopy(ConnectionNew, SqlBulkCopyOptions.KeepIdentity | SqlBulkCopyOptions.KeepNulls, null);
                bulkCopy.BulkCopyTimeout = 7200;
 
                //3.寫對應關系。如舊表的People列的數據,對應新表Human列,那么就寫bulkCopy.ColumnMappings.Add("People","Human")  
                //如果兩張表的結構一樣,那么對應關系就不用寫了。  
                //我是用哈希表存儲對應關系的,哈希表作為參數到傳入方法中,key的值用來存儲舊表的字段名,VALUE的值用來存儲新表的值  
                Hashtable ht = new Hashtable();
                ht.Add("ID", "ID2");
                ht.Add("NAME", "NAME2");//  
 
                foreach (string str in ht.Keys)
                {
                    bulkCopy.ColumnMappings.Add(str, ht[str].ToString());
                }
 
                //4.設置目標表名  
                bulkCopy.DestinationTableName = "Table_2";
 
                //額外,可不寫:設置一次性處理的行數。這個行數處理完后,會激發SqlRowsCopied()方法。默認為1  
                bulkCopy.NotifyAfter = 1;
 
                if (ExportInfo)
                {
                    //額外,可不寫:設置激發的SqlRowsCopied()方法,這里為bulkCopy_SqlRowsCopied  
                    bulkCopy.SqlRowsCopied += new SqlRowsCopiedEventHandler(bulkCopy_SqlRowsCopied);
                }
 
                //OK,開始傳數據! 
                DateTime dt = DateTime.Now;
                Console.WriteLine("開始時間:{0:yyyy-MM-dd HH:mm:ss,ms}", dt);
                bulkCopy.WriteToServer(sdr);
                DateTime dt2 = DateTime.Now;
                Console.WriteLine("結束時間:{0:yyyy-MM-dd HH:mm:ss,ms}", dt2);
                double time = dt2.Subtract(dt).TotalMilliseconds;
                Console.WriteLine("傳輸完畢!所用時間為:{0}(ms)", time);
                Console.Read();
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
                Console.Read();
            }
            finally
            {
                ConnectionNew.Close();
                ConnectionOld.Close();
            }
        }
 
        //激發的方法寫在外頭  
        private static void bulkCopy_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
        {
            //執行的內容。  
            //這里有2個元素值得拿來用  
            //e.RowsCopied,  //返回數值類型,表示當前已經復制的行數  
            //e.Abort,       //用於賦值true or false,用於停止賦值的操作  
            Console.WriteLine("當前已復制的行數:" + e.RowsCopied);
        }
    }
}

 

配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="DCString" value="Data Source=(local);Initial Catalog=db_Study;Persist Security Info=True;User ID=??;Password=??" />
    <add key="ExportInfo" value="false" />
  </appSettings>
</configuration>

 



 
 
************轉載:https://blog.csdn.net/yenange/article/details/35837247


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM