需將 SQL Server 2005 多張資料表資料遷移至 Oracle 10g,保留結構與資料完整性。採用 C# (ADO.NET) 批次搬移,支援交易控制與進度顯示。
using System;
using System.Data;
using System.Data.SqlClient;
using Oracle.DataAccess.Client; // ODP.NET
namespace DataMigration
{
public class ImportExportData
{
private readonly string _sqlConnStr = "Data Source=localhost;Initial Catalog=UserCenterV32;Integrated Security=SSPI;";
private readonly string _oraConnStr = "Data Source=Oracle11;User Id=DBO_USERCENTERV32;Password=DBO_USERCENTERV32;";
public void ExportAll()
{
// 依相依順序列出需遷移表名
string[] tables = { "Base_Sequence", "Base_Module", "Base_Role" /* ...更多表*/ };
foreach (var tbl in tables)
ExportTable(tbl);
}
public void ExportTable(string tableName, string customSql = null)
{
DataTable dt;
using (var sqlConn = new SqlConnection(_sqlConnStr))
using (var sqlCmd = new SqlCommand(customSql ?? $"SELECT * FROM {tableName}", sqlConn))
{
sqlConn.Open();
using (var adapter = new SqlDataAdapter(sqlCmd))
{
dt = new DataTable(tableName);
adapter.Fill(dt);
}
}
using (var oraConn = new OracleConnection(_oraConnStr))
{
oraConn.Open();
using (var tx = oraConn.BeginTransaction())
{
try
{
// 1. 清空目標表
using (var truncateCmd = new OracleCommand($"TRUNCATE TABLE {tableName}", oraConn, tx))
truncateCmd.ExecuteNonQuery();
// 2. 批次插入
string cols = string.Join(",", dt.Columns.Cast().Select(c => c.ColumnName));
string params = string.Join(",", dt.Columns.Cast().Select(c => ":" + c.ColumnName));
string insertSql = $"INSERT INTO {tableName} ({cols}) VALUES ({params})";
using (var insCmd = new OracleCommand(insertSql, oraConn, tx))
{
// 建立參數
foreach (DataColumn col in dt.Columns)
insCmd.Parameters.Add(col.ColumnName, GetOracleType(col.DataType));
foreach (DataRow row in dt.Rows)
{
for (int i = 0; i < dt.Columns.Count; i++)
insCmd.Parameters[i].Value = row[i] ?? DBNull.Value;
insCmd.ExecuteNonQuery();
}
}
tx.Commit();
Console.WriteLine($"表 {tableName} 遷移完成,共 {dt.Rows.Count} 筆。");
}
catch (Exception ex)
{
tx.Rollback();
Console.WriteLine($"表 {tableName} 遷移失敗: {ex.Message}");
throw;
}
}
}
}
private OracleDbType GetOracleType(Type netType)
{
// 簡易型別對應,實務需依實際欄位精細對應
if (netType == typeof(string)) return OracleDbType.Varchar2;
if (netType == typeof(int) || netType == typeof(long)) return OracleDbType.Int64;
if (netType == typeof(DateTime)) return OracleDbType.Date;
if (netType == typeof(decimal)) return OracleDbType.Decimal;
return OracleDbType.Varchar2;
}
}
}
| 環節 | 處理策略 |
|---|---|
| 交易控制 | Oracle 端開啟交易,全表插入成功才 Commit,失敗 Rollback 保證原子性 |
| 大量資料效能 | 建議改用 OracleBulkCopy (ODP.NET 2.0+) 或陣列繫結 ArrayBindCount 批次寫入 |
| 型別對應 | SQL Server datetime → Oracle DATE;uniqueidentifier → RAW(16);bit → NUMBER(1) |
| 身分欄位 | Oracle 12c 前無 Identity,需建立 Sequence + Trigger 或手動指派 |
| 編碼問題 | 連線字串加 `Unicode=True`,確保中文不亂碼 |
OracleBulkCopy 替代逐筆 `ExecuteNonQuery`,效能提升 10-50 倍。以 C# 撰寫異構資料庫遷移工具,靈活度高、易維護。核心在於交易保護、型別精確對應、大量資料批次寫入三大支柱。生產環境建議採用 OracleBulkCopy + 並行化架構,並建立完整驗證與回滾機制。