系列文章导航: 如何将数据导入到 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日