目前有两种主要的PostgreSQL的.NET驱动程序,分别是Npgsql和dotConnector for PostgreSQL(以下简称dotConnector),这两者都是第三方的.NET Provider,本文将大致讲解一下这两个驱动程序的安装方式,并讲解如何利用它们构建PDF.NET的驱动程序,使得PDF.NET数据开发框架可以支持访问PostgreSQL数据库。
一、安装PostgreSQL的.NET驱动程序
1,Npgsql的安装:
PostgreSQL数据库程序可以去官网 http://www.postgresql.org/ 下载,在写本篇文章的时候,最新版本已经是9.1了,我下载使用的是9.0.4. 下载安装以后,打开程序 Application Stack Builder,选择已经安装好的数据库以后,单击下一步进入到如下界面
在Datase Drivers选项中,这里选择Npgsql v2.0.11-1,其它驱动程序根据需要安装。选择好以后,按照提示一步步即可完整安装好.NET的数据驱动程序。
2,dotConnect For PostgreSQL 安装
在网上搜索一下这个驱动程序,我是从下面的地址安装的:
http://wzmcc.newhua.com/soft/92182.htm
安装文件名是 dcpostgresqlfree.exe,版本是 5.30.160,安装的时候会选择是否将程序集编译到GAC中。安装完成以后在安装目录会有几个简单的示例程序解决方案:
大家可以打开示例程序解决方案看看,都很简单,具体如何使用可以看本篇文章的下面部分。
二、构建PDF.NET For PostgreSQL驱动程序
根据上面的步骤,安装了.NET的PostgreSQL驱动程序以后,就可以直接按照示例来访问PostgreSQL数据库了,但这两种不同的驱动程序让我们难以选择使用哪一种,而且它们直接提供的ADO.NET实现用起来也不是十分方便,我们有必要将它们包装一下,简化使用方式。PDF.NET数据开发框架内置了MS DAAB类似的AdoHelper数据访问抽象类,所以只要继承该类就可以拥有PDF.NET强大的数据访问能力。
1,包装Ngpsql驱动程序
下面以Npgsql为例,看看如何让PDF.NET支持PostgreSQL。下面是贴出全部代码:
using
System;
using
System.Collections.Generic;
//
using System.Linq;
using
System.Text;
using
System.Data;
using
Npgsql ;
namespace
PWMIS.DataProvider.Data
{
///
<summary>
///
PostgreSQL数据访问类
///
</summary>
public
class
PostgreSQL : AdoHelper
{
///
<summary>
///
默认构造函数
///
</summary>
public
PostgreSQL()
{
//
//
TODO: 在此处添加构造函数逻辑
//
}
///
<summary>
///
获取当前数据库类型的枚举
///
</summary>
public
override
PWMIS.Common.DBMSType CurrentDBMSType
{
get
{
return
PWMIS.Common.DBMSType.PostgreSQL ; }
}
///
<summary>
///
创建并且打开数据库连接
///
</summary>
///
<returns>
数据库连接
</returns>
protected
override
IDbConnection GetConnection()
{
IDbConnection conn
=
base
.GetConnection();
if
(conn
==
null
)
{
conn
=
new
NpgsqlConnection (
base
.ConnectionString);
//
conn.Open ();
}
return
conn;
}
///
<summary>
///
获取数据适配器实例
///
</summary>
///
<returns>
数据适配器
</returns>
protected
override
IDbDataAdapter GetDataAdapter(IDbCommand command)
{
IDbDataAdapter ada
=
new
NpgsqlDataAdapter((NpgsqlCommand)command);
return
ada;
}
///
<summary>
///
获取一个新参数对象
///
</summary>
///
<returns>
特定于数据源的参数对象
</returns>
public
override
IDataParameter GetParameter()
{
return
new
NpgsqlParameter();
}
///
<summary>
///
获取一个新参数对象
///
</summary>
///
<param name="paraName">
参数名
</param>
///
<param name="dbType">
参数数据类型
</param>
///
<param name="size">
参数大小
</param>
///
<returns>
特定于数据源的参数对象
</returns>
public
override
IDataParameter GetParameter(
string
paraName, System.Data.DbType dbType,
int
size)
{
NpgsqlParameter para
=
new
NpgsqlParameter();
para.ParameterName
=
paraName;
para.DbType
=
dbType;
para.Size
=
size;
return
para;
}
///
<summary>
///
返回此 NpgsqlConnection 的数据源的架构信息。
///
</summary>
///
<param name="collectionName">
集合名称
</param>
///
<param name="restrictionValues">
请求的架构的一组限制值
</param>
///
<returns>
数据库架构信息表
</returns>
public
override
DataTable GetSchema(
string
collectionName,
string
[] restrictionValues)
{
using
(NpgsqlConnection conn
=
(NpgsqlConnection)
this
.GetConnection())
{
conn.Open();
if
(restrictionValues
==
null
&&
string
.IsNullOrEmpty(collectionName))
return
conn.GetSchema();
else
if
(restrictionValues
==
null
&&
!
string
.IsNullOrEmpty(collectionName))
{
if
(collectionName
==
"
Procedures
"
)
return
this
.getProcedures();
else
return
conn.GetSchema(collectionName);
//
Procedures
}
else
{
if
(collectionName
==
"
ProcedureParameters
"
)
return
getFunctionArgsInfo(restrictionValues[
2
]);
else
return
conn.GetSchema(collectionName, restrictionValues);
}
}
}
///
<summary>
///
预处理SQL语句,语句中不能包含"`"(反引号,tab键上面的那个符号)号,如果需要,请使用参数化查询。
///
</summary>
///
<param name="SQL"></param>
///
<returns></returns>
protected
override
string
PrepareSQL(
ref
string
SQL)
{
return
SQL.Replace(
"
[
"
,
"
\"
"
).Replace(
"
]
"
,
"
\"
"
);
}
///
<summary>
///
获取或者设置自增列对应的序列名称
///
</summary>
public
override
string
InsertKey
{
get
{
return
string
.Format(
"
select currval('\"{0}\"')
"
,
base
.InsertKey );
}
set
{
base
.InsertKey
=
value;
}
}
///
<summary>
///
定义获取PostgreSQL的函数参数的函数
///
<seealso cref="http://www.alberton.info/postgresql_meta_info.html"/>
///
</summary>
private
void
createFunctionArgsInfo()
{
//
由于函数定义语句较长,放到了资源文件中
string
sql
=
PWMIS.PostgreSQLClient.Properties.Resources.sql_function_args;
this
.SqlServerCompatible
=
false
;
this
.ExecuteNonQuery(sql);
}
///
<summary>
///
获取函数的参数信息
///
</summary>
///
<param name="functionName">
函数名
</param>
///
<returns></returns>
private
DataTable getFunctionArgsInfo(
string
functionName)
{
string
sql
=
string
.Format(
"
select * from function_args('{0}','public');
"
, functionName);
DataSet ds
=
null
;
try
{
ds
=
this
.ExecuteDataSet(sql);
}
catch
{
createFunctionArgsInfo();
ds
=
this
.ExecuteDataSet(sql);
}
DataTable dt
=
ds.Tables[
0
];
dt.Columns[
"
pos
"
].ColumnName
=
"
ordinal_position
"
;
dt.Columns[
"
argname
"
].ColumnName
=
"
PARAMETER_NAME
"
;
dt.Columns[
"
datatype
"
].ColumnName
=
"
DATA_TYPE
"
;
dt.Columns[
"
direction
"
].ColumnName
=
"
PARAMETER_MODE
"
;
dt.Columns.Add(
"
IS_RESULT
"
,
typeof
(
string
));
dt.Columns.Add(
"
CHARACTER_MAXIMUM_LENGTH
"
,
typeof
(
int
));
foreach
(DataRow row
in
dt.Rows)
{
if
(row[
"
PARAMETER_NAME
"
]
==
DBNull.Value) row[
"
PARAMETER_NAME
"
]
=
""
;
row[
"
IS_RESULT
"
]
=
row[
"
PARAMETER_NAME
"
].ToString()
==
"
RETURN VALUE
"
?
"
YES
"
:
"
NO
"
;
row[
"
PARAMETER_MODE
"
]
=
row[
"
PARAMETER_MODE
"
].ToString()
==
"
o
"
?
"
OUT
"
: row[
"
PARAMETER_MODE
"
].ToString()
==
"
i
"
?
"
IN
"
: row[
"
PARAMETER_MODE
"
];
}
return
dt;
}
private
DataTable getProcedures()
{
string
sql
=
@"
SELECT routine_name
FROM information_schema.routines
WHERE specific_schema NOT IN
('pg_catalog', 'information_schema')
AND type_udt_name != 'trigger';
"
;
return
this
.ExecuteDataSet(sql).Tables[
0
];
}
}
}
注意上面程序中的 PrepareSQL 方法,它将SQLSERVER格式的SQL语句转换成PostgreSQL支持的格式,SQLSERVER使用成对的中括号来限定对象名,而PostgreSQL使用双引号,尤其在对象名称使用了大小写混合的情况。另外程序为了支持获取数据库的架构信息,重写了AdoHelper的抽象方法GetSchema,有关PostgreSQL具体获取表架构信息的内容,请参看 http://www.alberton.info/postgresql_meta_info.html 。
2,包装dotConnect驱动程序
程序代码与使用Npgsql类似,区别主要是将上面代码中的Npgsql字样替换成PgSql即可,引用Devart.Data.dll,Devart.Data.PostgreSql.dll,使用下面的名称空间:
using
Devart.Data.PostgreSql;
由于dotConnect的驱动程序采用Oracle驱动程序的风格,要求SQL语句的参数使用“:”作为参数名称,而不是SqlServer样式的“@”,所以下面的方法需要重写:
///
<summary>
///
预处理SQL语句,语句中不能包含中括号,如果需要,请使用参数化查询。
///
</summary>
///
<param name="SQL"></param>
///
<returns></returns>
protected
override
string
PrepareSQL(
ref
string
SQL)
{
return
SQL.Replace(
"
[
"
,
"\""
).Replace(
"
]
"
,
"\""
).Replace(
"
@
"
,
"
:
"
);
}
public
override
string
GetParameterChar
{
get
{
return
"
:
"
;
}
}
到此为止,使用dotConnect做PDF.NET的PostgreSQL驱动程序也做好了。
三、使用PDF.NET For PostgreSQL驱动程序
1,使用配置
假定上面使用Npgsql和dotConnect驱动的程序分别是 PWMIS.PostgreSQLClient 程序集中的程序,名称分别是
PWMIS.DataProvider.Data.PostgreSQL
PWMIS.DataProvider.Data.dotConnectPostgreSQL
那么我们在应用程序配置文件里面如下使用即可:
使用Npgsql访问:
<
add
name
="ConnectionSetting"
connectionString
="server=192.168.XX.XX;User Id=postgres;password=XXXX;DataBase=XXDB"
providerName
="PWMIS.DataProvider.Data.PostgreSQL,PWMIS.PostgreSQLClient"
/>
使用dotConnect访问:
<
add
name
="ConnectionSetting"
connectionString
="server=192.168.XX.XX;User Id=postgres;password=XXXX;DataBase=XXDB"
providerName
="PWMIS.DataProvider.Data.dotConnectPostgreSQL,PWMIS.PostgreSQLClient"
/>
2,执行效率区别
使用这两个不同的提供程序数据访问效率有什么区别呢?经过测试,它们之间仅有细微的差别,Npgsql略微胜出,下面是测试程序建立过程:
首先在SqlMap.config文件中建立一个PostgreSQL的数据访问脚本:
<
Select
CommandName
="GetFundFeat"
Method
=""
CommandType
="Text"
Description
="获取业绩"
ResultClass
="DataSet"
>
<![CDATA[
SELECT * FROM GetFundTrend_FundAnalysis_FundFeat (#currentJJDM:String#,#OtherJJDM:String#)
]]>
</
Select
>
然后使用集成开发工具的代码生成器生成一个类中下面的方法:
public
DataSet GetFundFeat(String currentJJDM , String OtherJJDM )
{
//
获取命令信息
CommandInfo cmdInfo
=
Mapper.GetCommandInfo(
"
GetFundFeat
"
);
//
参数赋值,推荐使用该种方式;
cmdInfo.DataParameters[
0
].Value
=
currentJJDM;
cmdInfo.DataParameters[
1
].Value
=
OtherJJDM;
//
参数赋值,使用命名方式;
//
cmdInfo.SetParameterValue("@currentJJDM", currentJJDM);
//
cmdInfo.SetParameterValue("@OtherJJDM", OtherJJDM);
//
执行查询
return
CurrentDataBase.ExecuteDataSet(CurrentDataBase.ConnectionString, cmdInfo.CommandType, cmdInfo.CommandText , cmdInfo.DataParameters);
//
}
//
End Function
最后以不同的Pgsql驱动程序运行程序,查看执行的
SQL日志:
使用dotConnect访问:
//
2011
/
5
/
30
16
:
52
:
44
@AdoHelper 执行命令:
SQL
=
"
SELECT * FROM GetFundTrend_FundAnalysis_FundFeat (:currentJJDM,:OtherJJDM)
"
//命令类型:Text
//2个命令参数:
Parameter
[
"currentJJDM"
]
=
"
KF0355
"
//DbType
=
AnsiString
Parameter
[
"OtherJJDM"
]
=
"
000001,399001,H11020,000300
"
//DbType
=
AnsiString
//
2011
/
5
/
30
16
:
52
:
44
@AdoHelper :Execueted Time(ms):
448
使用Npgsql访问:
//
2011
/
5
/
30
16
:
58
:
17
@AdoHelper 执行命令:
SQL
=
"
SELECT * FROM GetFundTrend_FundAnalysis_FundFeat (@currentJJDM,@OtherJJDM)
"
//命令类型:Text
//2个命令参数:
Parameter
[
"@currentJJDM"
]
=
"
KF0180
"
//DbType
=
String
Parameter
[
"@OtherJJDM"
]
=
"
000001,399001,H11020,000300
"
//DbType
=
String
//
2011
/
5
/
30
16
:
58
:
17
@AdoHelper :Execueted Time(ms):
405
有关PDF.NET数据开发框架的详细信息,请看官网说明:http://www.pwmis.com/sqlmap