您好,欢迎访问一九零五行业门户网

如何将数据导入到 SQL Server Compact Edition 数据库中(三)

系列文章导航: 如何将数据导入到 sql server compact edition 数据库中(一) 如何将数据导入到 sql server compact edition 数据库中(二) 摘要:时隔近半年了,不知道大家是否还记得,我在本系列的第一篇文章的总结中提到,创建 sql server ce 数据库表
系列文章导航:
如何将数据导入到 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 语句的主要代码:
/// 
/// 生成创建数据库表结构的 sql 语句。
/// 
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 数据类型。这个方法的代码如下所示:
/// 
/// 从 .net 数据类型获取对应的 sql server ce  类型名称。
/// 
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));
    }
}
当然,仅仅知道列的数据类型还不够,我们需要为某些列的数据类型加上长度、精度或小数位数等列大小信息。可以通过下面的方法实现:
/// 
/// 从 columnschemarow 获取 sql server ce 数据类型。
/// 
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(5) not null,
  [companyname] nvarchar(40) not null,
  [contactname] nvarchar(30) null,
  [contacttitle] nvarchar(30) null,
  [address] nvarchar(60) null,
  [city] nvarchar(15) null,
  [region] nvarchar(15) null,
  [postalcode] nvarchar(10) null,
  [country] nvarchar(15) null,
  [phone] nvarchar(24) null,
  [fax] nvarchar(24) null,
  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 数据库所有用户表名的数组:
/// 
/// 从一个打开的 sql server 数据库连接获取数据库的表名数组。
/// 
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';
liststring> tablenames = new liststring>();
    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日
其它类似信息

推荐信息