如何將數據導入到 SQL Server Compact Edition 數據庫中(三)

系列文章導航:
如何將數據導入到 SQL Server Compact Edition 數據庫中(一)
如何將數據導入到 SQL Server Compact Edition 數據庫中(二)

摘要:時隔近半年了,不知道大家是否還記得,我在本系列的第一篇文章的總結中提到,創建 SQL Server CE 數據庫表結構的 SQL 語句是可以自動生成的。那麼本系列的第三篇文章就向大家介紹一種比較簡單的方法。

ADO.NET 中的 IDataReader.GetSchemaTable 方法可以返回一個 DataTable,它描述了 IDataReader 查詢結果中各列的元數據。列的元數據包含了列的名稱、數據類型、大小、是否爲主鍵字段、是否爲自動增長字段……等等。有了這些元數據,我們就可以通過編寫幾段 C#/VB.NET 代碼,實現創建 SQL Server CE 數據庫表結構的 SQL 語句的自動生成。以下方法是生成創建表 SQL 語句的主要代碼:

/// <summary>
/// 生成創建數據庫表結構的 SQL 語句。
/// </summary>
private static string GenerateTableSchemaSql(IDbConnection connection, string queryString)
{
    StringBuilder tableSql 
= new StringBuilder(); 

    IDbCommand command 
= connection.CreateCommand();
    command.CommandText 
= queryString; 

    
try
    {
        
/* 獲取查詢結果各列的元數據 */
        DataTable schemaTable 
= null;
        
using (IDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo))
        {
            schemaTable 
= reader.GetSchemaTable();
        } 

        
/* 生成創建表定義語句 */
        
string tableName = schemaTable.Rows[0]["BaseTableName"].ToString();
        tableSql.Append(
"CREATE TABLE [").Append(tableName).AppendLine("] ("); 

        
/* 生成各列的定義語句 */
        
string columnName;
        
string allowDBNull;
        DataRow row;
        
bool hasKey = false;
        StringBuilder sbPKFields 
= new StringBuilder();
        
for (int i = 0; i < schemaTable.Rows.Count; i++)
        {
            
if (i != 0) tableSql.AppendLine(","); 

            row 
= schemaTable.Rows[i];
            columnName 
= (string)row["ColumnName"];
            allowDBNull 
= ((bool)row["AllowDBNull"== true ? "NULL" : "NOT NULL"); 

            
if ((bool)row["IsKey"])
            {
                sbPKFields.AppendFormat(
"[{0}],", columnName);
                hasKey 
= true;
            }
            tableSql.AppendFormat(
"  [{0}] {1} {2}", columnName, GetSqlCeDataType(row), allowDBNull);
        } 

        
/* 生成主鍵約束語句 */
        
if (hasKey)
        {
            
string pkFields = sbPKFields.ToString().TrimEnd(',');
            tableSql.AppendLine(
",");
            tableSql.Append(
"  CONSTRAINT PK_").Append(tableName.Replace(" ", "_")).Append(" PRIMARY KEY(").Append(pkFields).AppendLine(")");
        }
        tableSql.AppendLine(
");");
    }
    
catch (Exception ex)
    {
        Debug.WriteLine(ex);
    } 

    
return tableSql.ToString();
}

同樣的,該方法也使用了 ADO.NET 的接口類,不依賴於具體的數據庫類型。該方法的核心就是通過 IDataReader.GetSchemaTable 方法獲取查詢結果各列元數據,相關代碼如下:

IDbCommand command = connection.CreateCommand();
command.CommandText 
= queryString;
DataTable schemaTable 
= null;
using (IDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo))
{
    schemaTable 
= reader.GetSchemaTable();
}

首先,IDbCommand 的 CommandText 屬性一般是針對一個表的 SELECT 查詢語句,如:SELECT * FROM Customers。其次,IDbCommand.ExecuteReader 方法必須傳入 CommandBehavior.KeyInfo 參數,這樣才能獲取到列的主鍵元數據。最後,通過 IDataReader.GetSchemaTable 方法返回一個包含查詢結果所有列的元數據的 DataTable。關於 IDataReader.GetSchemaTable 方法的詳細使用說明,請閱讀《HOW TO:使用 DataReader GetSchemaTable 方法和 Visual C# .NET 檢索列架構》

IDataReader.GetSchemaTable 返回的 SchemaTable 對列數據類型的描述是用相應的 .NET 數據類型,如 SQL Server CE 的 int 類型對應的是 .NET 的 System.Int32 類型。另外需要注意的是,由於 Windows Mobile 只支持 Unicode 編碼,因此 SQL Server CE 只支持 NChar, NVarChar 和 NText 等 Unicode 字符數據類型,而不支持 Char, VarChar 和 Text 等非 Unicode 字符數據類型。所以,我們需要編寫一個方法,它根據列的 .NET 數據類型找到對應的 SQL Server CE 數據類型。這個方法的代碼如下所示:

/// <summary>
/// 從 .NET 數據類型獲取對應的 SQL Server CE  類型名稱。
/// </summary>
private static string GetSqlCeNativeType(Type systemType)
{
    
string typeName = systemType.ToString();
    
switch (typeName)
    {
        
case "System.Boolean":
            
return "bit";
        
case "System.Byte":
            
return "tinyint";
        
case "System.Byte[]":
            
return "image";
        
case "System.DateTime":
            
return "datetime";
        
case "System.Decimal":
            
return "numeric";
        
case "System.Double":
            
return "float";
        
case "System.Guid":
            
return "uniqueidentifier";
        
case "System.Int16":
            
return "smallint";
        
case "System.Int32":
            
return "integer";
        
case "System.Int64":
            
return "bigint";
        
case "System.Single":
            
return "real";
        
case "System.String":
            
return "nvarchar";
        
default:
            
throw new ApplicationException(string.Format("找不到 {0} 類型對應的 SQL Server CE 數據類型。", typeName));
    }
}

當然,僅僅知道列的數據類型還不夠,我們需要爲某些列的數據類型加上長度、精度或小數位數等列大小信息。可以通過下面的方法實現:

/// <summary>
/// 從 ColumnSchemaRow 獲取 SQL Server CE 數據類型。
/// </summary>
private static string GetSqlCeDataType(DataRow columnSchemaRow)
{
    Type type 
= columnSchemaRow["DataType"as Type;
    
string dataType = GetSqlCeNativeType(type);
    
switch (dataType)
    {
        
case "numeric":
            Int16 precision 
= (Int16)columnSchemaRow["NumericPrecision"];
            Int16 scale 
= (Int16)columnSchemaRow["NumericScale"];
            Int32 colsize 
= (Int32)columnSchemaRow["ColumnSize"];
            
if (precision != 0 && scale != 0 && scale != 255)
            {
                dataType 
= string.Format("{0}({1},{2})", dataType, precision, scale);
            }
            
else if (scale == 255 && colsize == 8)
            {
                dataType 
= "money";
            }
            
break;
        
case "nvarchar":
            
int columnSize = (int)columnSchemaRow["ColumnSize"];
            
if (columnSize > 4000)
            {
                dataType 
= "ntext";
            }
            
else
            {
                dataType 
= string.Format("{0}({1})", dataType, columnSize);
            }
            
break;
    }
    
return dataType;
}

關於 SQL Server 2005 Compact Edition 數據類型的描述,詳細請參考聯機叢書。使用上面的幾段代碼,對 SQL Server 2000 自帶的 Northwind 數據庫的 Customers 表生成創建數據庫表的 SQL 語句,生成結果如下:

CREATE TABLE [Customers] (
  
[CustomerID] nvarchar(5NOT NULL,
  
[CompanyName] nvarchar(40NOT NULL,
  
[ContactName] nvarchar(30NULL,
  
[ContactTitle] nvarchar(30NULL,
  
[Address] nvarchar(60NULL,
  
[City] nvarchar(15NULL,
  
[Region] nvarchar(15NULL,
  
[PostalCode] nvarchar(10NULL,
  
[Country] nvarchar(15NULL,
  
[Phone] nvarchar(24NULL,
  
[Fax] nvarchar(24NULL,
  
CONSTRAINT PK_Customers PRIMARY KEY([CustomerID])
);

對於 SQL Server 2000,我們可以從信息架構視圖查詢 INFORMATION_SCHEMA.TABLES 出數據庫有哪些表,並一次性對所有表進行生成。以下是 INFORMATION_SCHEMA.TABLES 視圖各列的說明:

列名 數據類型 說明
TABLE_CATALOG nvarchar(128) 表限定符。
TABLE_SCHEMA nvarchar(128) 包含該表的架構的名稱。
TABLE_NAME sysname 表名。
TABLE_TYPE varchar(10) 表的類型。可以是 VIEW 或 BASE TABLE。

我們可以通過以下方法獲得 Northwind 數據庫所有用戶表名的數組:

/// <summary>
/// 從一個打開的 SQL Server 數據庫連接獲取數據庫的表名數組。
/// </summary>
private static string[] GetTableNames(IDbConnection connection)
{
    IDbCommand command 
= connection.CreateCommand(); 

    
// 從 SQL Server 信息架構視圖獲取 Northwind 數據庫所有表的名稱
    command.CommandText = @"SELECT * FROM INFORMATION_SCHEMA.TABLES 
    WHERE TABLE_TYPE='BASE TABLE' AND TABLE_CATALOG='Northwind'
"

    List
<string> tableNames = new List<string>();
    
using (IDataReader reader = command.ExecuteReader())
    {
        
while (reader.Read())
        {
            tableNames.Add(reader[
"TABLE_NAME"].ToString());
        }
    }
    
return tableNames.ToArray();
}

有了 GetTableNames 方法,我們就可以一次性對 Northwind 數據庫的所有用戶表生成相應的創建 SQL Server CE 數據庫表結構的 SQL 語句。

static void Main(string[] args)
{
    
string connectionString = "Data Source=(local);Initial Catalog=Northwind;Integrated Security=True";
    IDbConnection connection 
= new SqlConnection(connectionString);
    connection.Open(); 

    
string[] tableNames = GetTableNames(connection); 

    
string queryString, createTableSql;
    
foreach (string tableName in tableNames)
    {
        queryString 
= string.Format("select * from [{0}]", tableName);
        createTableSql 
= GenerateTableSchemaSql(connection, queryString); 

        Console.WriteLine(createTableSql);
        Debug.WriteLine(createTableSql);
    } 

    connection.Close();
    Console.Read();
}

示例程序運行效果如下圖所示:


總結:閱讀完本文,相信你已經瞭解瞭如何利用 ADO.NET 的 IDataReader.GetSchemaTable 方法獲得服務器端數據庫表的元數據,並用於生成對應的創建 SQL Server CE 數據庫表的 SQL 語句。本系列文章可能還會有更精彩的續篇,我會將平時積累的關於 SQL Server CE 數據導入的一些經驗充實到本系列中。

示例代碼下載:sqlce_data_import3.rar

更新記錄:
2008-2-9 修正對money數據類型的支持,修正對包含空格的表名的支持。

作者:黎波
博客:http://upto.cnblogs.com/
日期:2008年1月31日

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章