ado.net之SQLServer和Oracle (sys_cursor) 数据库链接——获取结果集方式对比

ADO链接:SQLServer与Oracle,重点是在获取多行多列的结果集方式上不同:

链接Oracle时,需要以ref游标的方式获取结果集(数据库端必须编写package或者procedure,并且返回ref游标,ADO数据链接程序则需要定义一个OracleDbType.RefCursor类型的参数,接收数据库端的指向结果集的ref游标),而链接SQLServer时,没有这一要求。

数据库链接方法被封装在SqlHelper类中:

using System.Data;
using Oracle.ManagedDataAccess.Client;

namespace DAL
{
    public class SqlHelper
    {
        //数据库连接字符串
        //SqlServer
        private static string ConnString = "Server=.;DataBase=HotelDB;Uid=sa;Pwd=sj123";
        //Oracle
        //private static string ConnString = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=sajet1)));Persist Security Info=True;User ID=sajet;Password=tech;";
        //这里只展示获取结果集的方法,其他方法不展示
        public static OracleDataReader GetResult(string sql,OracleParameter[] param,bool flag)
        {
            OracleConnection conn = new OracleConnection(connString);
            OracleCommand cmd = new OracleCommand(sql, conn);
            if (flag)
            {
                cmd.CommandType = CommandType.StoredProcedure;
            }
            if (param != null)
            {
                cmd.Parameters.AddRange(param);
            }
            try
            {
                conn.Open();
                return cmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (Exception ex)
            {
                conn.Close();
                throw ex;
            }
        }
    }
}
View Code

DishService.cs :调用SQLHelper类,负责数据的传递(接收应用程序的数据并上传数据库,或将数据库的数据取出来返回给应用程序)

[这里以DishService类为例,可以改成任意类]

SQLServer:不需要引用外部的dll

public List<DishCategory> GetDishCategories()
{
    string sql = "select CategoryId,CategoryName from dishcategory";
    SqlDataReader objReader = SqlHelper.GetResult(sql);
    List<DishCategory> dishList = new List<DishCategory>();
    while(objReader.Read())
    {
        dishList.Add(new DishCategory()
        {
            CategoryId = Convert.ToInt32(objReader["CategoryId"]),
            CategoryName = objReader["CategoryName"].ToString()
        });
    }
    objReader.Close();
    return dishList;
}

上面的sql语句也能以存储过程的方式写到SQLServer上:

use HotelDB
go
if exists(select * from sysobjects where name='usp_GetAllDishCategory')
drop procedure usp_GetAllDishCategory
go
create procedure usp_GetAllDishCategory
as
begin
    select categoryid,categoryname from DishCategory
    --这里返回一张表的结果集
end
go

ADO方法调用上面的存储过程:

public List<DishCategory> GetDishCategories()
{
    SqlDataReader objReader = SqlHelper.GetResult("usp_GetAllDishCategory",null,true);
    List<DishCategory> dishList = new List<DishCategory>();
    while(objReader.Read())
    {
        dishList.Add(new DishCategory()
        {
            CategoryId = Convert.ToInt32(objReader["CategoryId"]),
            CategoryName = objReader["CategoryName"].ToString()
        });
    }
    objReader.Close();
    return dishList;
}

Oracle:需要引用外部的dll(这里用的是Oracle.ManagedDataAccess.dll)

要获取结果集,必须编写存储过程,返回指向结果集的引用游标。[Oracle提供REF CURSOR,通过引用游标可以实现在程序间传递结果集的功能]

CREATE OR REPLACE procedure SAJET.usp_GetAllDishCatetory
(
    dish_cur out sys_refcursor
)
is
begin
     --返回指向结果集的游标   
    open dish_cur for select CategoryId,CategoryName from DishCategory;
    --close dish_cur;这里千万不能画蛇添足,不能关闭游标,否则数据库将释放游标指向的内存空间,ado的OracleCommand类的ExecuteReader()方法接收不到任何数据。
end usp_GetAllDishCatetory;

ADO方法调用上面的存储过程:

public List<DishCategory> GetDishCategories()
{
    OracleParameter cur_result = new OracleParameter(":dish_cur", OracleDbType.RefCursor);
    //默认输入参数不需要指明指向类型,如果是输出参数需要指明参数指向类型
    cur_result.Direction = ParameterDirection.Output;
    OracleParameter[] param = new OracleParameter[] { cur_result }; 
    OracleDataReader objReader = SqlHelper.GetResult("SAJET.usp_GetAllDishCatetory",param,true);
    List<DishCategory> dishList = new List<DishCategory>();
    while (objReader.Read())
    {
        dishList.Add(new DishCategory()
        {
            CategoryId = Convert.ToInt32(objReader["CategoryId"]),
            CategoryName = objReader["CategoryName"].ToString()
        });
    }
    objReader.Close();
    return dishList;
}

补充:应用程序中如何释放数据库资源?

关闭数据库连接对象--->数据库连接一旦显式关闭,那么这个连接进程会在服务器端也进行强制挂起,并进入关闭的队列,等待关闭。[所以不用担心数据库端的游标不会被关闭]

这里要强调的是,XXXDataReader在获取数据的时候,应用程序与数据库的连接不会被断开,但数据被取完后,需要关闭读取器。

原理:应用程序发现读取器关闭后

objReader.Close();

读取器对象会通过下面的方式:

cmd.ExecuteReader(CommandBehavior.CloseConnection);

触发数据库连接对象conn.Close()方法。

原文地址:https://www.cnblogs.com/pandora2050/p/15134277.html