执行SQL语句并处理结果
向数据库发出执行SQL的请求时,需要使用NpgsqlCommand实例发出查询,服务端执行完成后将返回一个NpgsqlDataReader实例,该实例包括查询的结果。
执行查询
使用NpgsqlCommand执行查询:
//将返回两个结果集
using (var cmd = new NpgsqlCommand("SELECT ...; SELECT ...",conn))
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// Read first resultset
}
reader.NextResult();
while (reader.Read())
{
// Read second resultset
}
}
读取结果
获取单一结果
执行查询,并返回查询所返回的结果集中第一行的第一列。 所有其他的列和行将被忽略。此方法适合使用 ExecuteScalar 方法从数据库中检索单个值(例如一个聚合值),比如统计数量。
对于查询单个字段,不包括函数的 select 语句,例如 select a字段 from 表A ,如果不存在值, DbCommand.ExecuteScalar 方法的返回值是 null,调用者需要使用 result == null 来判断。
对于使用函数的select 语句,例如select sum(a字段) from 表A,如果不存在值,DbCommand.ExceuteScalar 方法的返回值是 DBNull.Value,调用者需要用 result is DBNull 或者 result == DBNull.Value 来判断。
string sql = "select count(*) from test";
using (var cmd = new NpgsqlCommand(sql,conn))
{
int count = Convert.ToInt32(cmd.ExecuteScalar()); //将结果转换成整数
}
使用DataReader获取结果
驱动程序获取某个查询的结果集,并以流的方式返回给客户端。示例:
//将返回两个结果集
using (var cmd = new NpgsqlCommand("SELECT ...; SELECT ...",conn))
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// Read first resultset
for (i = 0; i < reader.FieldCount; i++)
{
Console.Write("{0} \t", reader[i]); //获得字段名
string fieldType = reader.GetFieldType(i).ToString(); //获得指定字段的类型
}
var fieldValue = reader["fieldName"]; // 获得指定字段的值(fieldName是表的某个字段)
}
reader.NextResult();
while (reader.Read()) {
// Read second resultset
......
}
reader.Close();
}
使用NpgsqlCommand对象
在使用NpgsqlCommand,需要注意以下问题:
NpgsqlCommand传入SQL命令是在构造函数中进行的,因此最好一次执行对应一个NpgsqlCommand实例。为了避免.NET垃圾回收不及时,可以指定空间回收时机使得命令执行完成且结果获取之后释放NpgsqlCommand空间,可以通过using(……)方式或者try-finally来指定:
using (var cmd = new NpgsqlCommand(“......", conn))
using (NpgsqlDataReader reader = cmd.ExecuteReader()){
......
}
或者:
var cmd = new NpgsqlCommand(“......");
Try
{
NpgsqlDataReader reader = cmd.ExecuteReader();
Try
{
......
}
Finally
{
if (reader != null)
((IDisposable)reader).Dispose();
}
}
Finally
{
if (cmd != null)
((IDisposable)cmd).Dispose();
通过上述两种方式都可以进行及时的空间回收,不会造成空间浪费,并且可以保证使用安全。另外,也可以进行NpgsqlCommand的复用,即可以多次使用一个NpgsqlCommand实例,可以在打开连接时创建NpgsqlCommand然后在连接的整个生命周期内使用它,每次在执行之前可以修改NpgsqlCommand的参数:
cmd.Connection = conn; //设置连接
cmd.CommandType = CommandType.Text; //指明命令类型
cmd.CommandText = "selelct * from data"; //SQL语句
NpgsqlDataReader reader = cmd.ExecuteReader();
但是这用方式要注意使用新连接时,要手动断掉旧链接。
如果在处理NpgsqlDataReader 时需要执行查询,可以创建另一个NpgsqlCommand来执行。
如果使用多线程 ,并且有多个线程正在使用数据库,则每个线程必须使用单独的NpgsqlCommand.,建议每个命令使用单独的NpgsqlCommand,保证安全。
使用完NpgsqlCommand应该及时释放空间,以及及时断开连接。
使用NpgsqlDataReader对象
使用NpgsqlDataReader 接口时必须考虑下面的问题:
- NpgsqlDataReader 对象是NpgsqlCommand对象在执行SQL语句后返回的一个结果对象,当结果集有多个时,默认指向的是第一个结果集,如果要访问下一个结果集时,需要使用NpgsqlDataReader 的NextResult方法;在某一个结果集中,通过不断调用NpgsqlDataReader 的Read方法,依次获取该结果集的一条记录,构建NpgsqlDataReader 对象的结构,可以通过NpgsqlDataReader 下标数字的方法获取字段信息,通过NpgsqlDataReader 下标字段名的方法获取值。
- NpgsqlDataReader 的Read方法,保证了对一个结果集的一条记录只访问一次。
- 在结束对一个 NpgsqlDataReader 的处理后,必须调用 close()来关闭它,并及时释放空间。
- 为了保证使用安全和线程安全,最好是一个NpgsqlCommand对应一个NpgsqlDataReader 对象,其实一个NpgsqlDataReader 对象就是由NpgsqlCommand执行产生的。当使用那个创建NpgsqlDataReader 的 NpgsqlCommand做另一个查询请求, 当前打开的 NpgsqlDataReader 实例不会自动关闭,此处小心使用。
执行更新
要更改数据(执行一个insert,update或者delete),可以使用NpgsqlCommand对象的 ExecuteNonQuery() 方法. ExecuteNonQuery() 方法类似于发出 select语句的 ExecuteReader()方法,不过,它不返回 NpgsqlDataReader ,它返回的是:
对于Update、insert、Delete语句执行成功是返回值为该命令所影响的行数,如果影响的行数是0,则返回值就是0;
对于所有其他类型的语句,返回值为-1;
如果发生回滚,返回值也为-1;
删除
string sql = "delete from test where id=1";
NpgsqlCommand cmd = new NpgsqlCommand(sql, conn);
cmd .ExecuteNonQuery();
更新
string sql = "update test set price=300 where id=1";
NpgsqlCommand cmd = new NpgsqlCommand(sql, conn);
cmd .ExecuteNonQuery();
插入
插入单行:
string sql = "insert into test values (1,200)";
NpgsqlCommand cmd = new NpgsqlCommand(sql, conn);
cmd .ExecuteNonQuery();
其中,SQL语句的参数,可以通过格式化字符串的方式去设置与替换,这是最简单的调用方式。当然也可以使用指定参数的方式去调用,后面存储过程一节会介绍这种方式。
创建或修改数据库对象
要创建、更改或者删除一个类似表或者视图这样的数据库对象, 仍然可以使用 ExecuteNonQuery() 方法,但是返回值只返回-1。
例如DROP表:
string sql = "DROP TABLE mytable";
NpgsqlCommand cmd = new NpgsqlCommand(sql, conn);
cmd .ExecuteNonQuery();
DROP数据库:
string sql = "DROP DATABASE mydatabase";
NpgsqlCommand cmd = new NpgsqlCommand(sql, conn);
cmd .ExecuteNonQuery(); s
小结
总结来说,SQL语句的主要执行对象就是NpgsqlCommand对象,只不过具体的执行过程不同,针对查询功能,调用的是NpgsqlCommand. ExecuteScalar功能或者NpgsqlCommand.ExecuteReader功能,查询返回的结果会返回一个NpgsqlDataReader对象,可以从这个对象里去获取数据;而其它类型的SQL,则使用NpgsqlCommand.ExecuteNonQuery功能,在针对数据记录的增删改操作,会返回受影响的记录数量,其它操作比如针对数据库对象的操作,返回-1。