iBatis.Net实现返回DataTable和DataSet对象

如题。要返回一个ADO.NET对象好像没有使用ORM的必要,而且从编程的角度看这样的实现一点也不OO,但是实际的开发场景中还是会碰到这种需求的。下面我就借鉴前人的经验,结合实际的示例,再总结一下。如果您认真看完,应该可以体会得到我的一些尝试,而不是人云亦云的照搬代码。

1、获得DbCommand对象

对于SQL语句,方法如下:

  /// <summary>
        /// SQL语?句?,?获?取?DbCommand
        /// </summary>
        /// <param name="sqlMapper"></param>
        /// <param name="statementName"></param>
        /// <param name="paramObject"></param>
        /// <returns></returns>
        protected virtual IDbCommand GetDbCommand(ISqlMapper sqlMapper, string statementName, object paramObject)
        {
            IStatement statement = sqlMapper.GetMappedStatement(statementName).Statement;
            IMappedStatement mapStatement = sqlMapper.GetMappedStatement(statementName);
            ISqlMapSession session = new SqlMapSession(sqlMapper);

            if (sqlMapper.LocalSession != null)
            {
                session = sqlMapper.LocalSession;
            }
            else
            {
                session = sqlMapper.OpenConnection();
            }

            RequestScope request = statement.Sql.GetRequestScope(mapStatement, paramObject, session);
            mapStatement.PreparedCommand.Create(request, session as ISqlMapSession, statement, paramObject);
            IDbCommand cmd = session.CreateCommand(CommandType.Text);
            cmd.CommandText = request.IDbCommand.CommandText;
            //return request.IDbCommand;
            return cmd;
        }

对于存储过程,因为对于参数类型的不同,需要多几步处理(因为需要多维护一个参数字典和其对应的ParameterDirection字典):


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

/// <summary>

/// 获取DbCommand,主要是针对存储过程

/// </summary>

/// <param name="sqlMapper"></param>

/// <param name="statementName"></param>

/// <param name="paramObject">参数</param>

/// <param name="dictParam">参数字段</param>

/// <param name="dictParmDirection">ParameterDirection字典</param>

/// <param name="cmdType"></param>

/// <returns></returns>

protected virtual IDbCommand GetDbCommand(ISqlMapper sqlMapper, string statementName, object paramObject, IDictionary dictParam, IDictionary<string, ParameterDirection> dictParmDirection, CommandType cmdType)

{

    if (cmdType == CommandType.Text)

    {

        return GetDbCommand(sqlMapper, statementName, paramObject);

    }

    IStatement statement = sqlMapper.GetMappedStatement(statementName).Statement;

    IMappedStatement mapStatement = sqlMapper.GetMappedStatement(statementName);

    ISqlMapSession session = new SqlMapSession(sqlMapper);

    if (sqlMapper.LocalSession != null)

    {

        session = sqlMapper.LocalSession;

    }

    else

    {

        session = sqlMapper.OpenConnection();

    }

    RequestScope request = statement.Sql.GetRequestScope(mapStatement, paramObject, session);

    mapStatement.PreparedCommand.Create(request, session as ISqlMapSession, statement, paramObject);

    IDbCommand cmd = session.CreateCommand(cmdType);

    cmd.CommandText = request.IDbCommand.CommandText;

    if (cmdType != CommandType.StoredProcedure || dictParam == null)

    {

        return cmd;

    }

    foreach (DictionaryEntry de in dictParam) //存储过程

    {

        string key = de.Key.ToString();

        IDbDataParameter dbParam = cmd.CreateParameter();

        dbParam.ParameterName = key;

        dbParam.Value = de.Value;

        if (dictParmDirection != null && dictParmDirection.ContainsKey(key))

        {

            dbParam.Direction = dictParmDirection[key]; //ParameterDirection

        }

        cmd.Parameters.Add(dbParam);

    }

    return cmd;

}

代码写得可能还有改进的必要,有需要从事这方面开发的童鞋,如果您看着有更好的办法请不吝赐教。

备注:

a、对于1.6.1之前的版本,获得命令的方式可以通过RequestScope的IDbCommand属性,但是1.6.1版本的IDbCommand属性返回的是IBatisNet.DataMapper.Commands.DbCommandDecorator对象,您可以注释代码验证一下。

b、网上有些文章贴的方法返回的DbCommand对象都是对于拼接SQL语句而言,没有实现获取存储过程的DbCommand(有参数无参数的都要考虑)。本文在原有资料的基础上,尝试着做出改进,目前支持SQL语句和存储过程。

2、返回DataSet对象

通过SQL语句,获取DataSet:


1

2

3

4

5

public DataSet GetDSPerson(int id)

   {

       string sql = this.GetRuntimeSql(this.SqlMapper, this.GetStatementName("GetDSPerson"), id);

       return this.QueryForDataSet(this.SqlMapper, this.GetStatementName("GetDSPerson"), id);

   }

XML配置:


1

2

3

4

<select id="GetDSPerson" parameterClass="int" resultClass="System.Data.DataSet">

  <include refid="CommonPersonColumns4Select"></include>

  WHERE 1=1 AND Id=$id$

</select>

客户端的调用:


1

2

3

int id = 1;

DataSet ds = ServiceFactory.CreatePersonService().GetDSPerson(id);

Console.WriteLine(ds.GetXml());

执行结果返回如下:

3、返回DataTable对象

a、通过SQL语句

      /// <summary>
        ///  通?用?的?执′行DSQL语?句?以?DataTable的?方?式?得?到?返う?回?的?结á果?(xml文?件t中D参?数簓要癮使?用?$标括?记?的?占?位?参?数簓)
        /// </summary>
        /// <param name="sqlMapper"></param>
        /// <param name="statementName"></param>
        /// <param name="paramObject"></param>
        /// <returns></returns>
        protected virtual DataTable QueryForDataTable(ISqlMapper sqlMapper, string statementName, object paramObject)
        {
            DataSet ds = new DataSet();
            bool isSessionLocal = false;
            IDalSession session = sqlMapper.LocalSession;
            if (session == null)
            {
                session = new SqlMapSession(sqlMapper);
                session.OpenConnection();
                isSessionLocal = true;
            }

            IDbCommand cmd = GetDbCommand(sqlMapper, statementName, paramObject);//SQL text command

            try
            {
                cmd.Connection = session.Connection;
                IDbDataAdapter adapter = session.CreateDataAdapter(cmd);
                adapter.Fill(ds);
            }
            finally
            {
                if (isSessionLocal)
                {
                    session.CloseConnection();
                }
            }

            return ds.Tables[0];
        }

这个相对简单,因为前面2中已经得到了DataSet,DataTable的提取就轻而易举了。

b、通过含OUTPUT参数的存储过程

这个地方主要就是改进后的GetDbCommand重载方法的使用,


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

/// <summary>

  /// 查询返回DataTable,对于包括OUTPUT参数的存储过程同样适用

  /// </summary>

  /// <param name="sqlMapper"></param>

  /// <param name="statementName"></param>

  /// <param name="paramObject">参数</param>

  /// <param name="dictParam">参数字典</param>

  /// <param name="dictParamDirection">ParameterDirection字典</param>

  /// <param name="htOutPutParameter">返回的Output参数值哈希表</param>

  /// <returns></returns>

  protected virtual DataTable QueryForDataTable(ISqlMapper sqlMapper, string statementName, object paramObject, IDictionary dictParam, IDictionary<string, ParameterDirection> dictParamDirection, out Hashtable htOutPutParameter)

  {

      DataSet ds = new DataSet();

      bool isSessionLocal = false;

      ISqlMapSession session = sqlMapper.LocalSession;

      if (session == null)

      {

          session = new SqlMapSession(sqlMapper);

          session.OpenConnection();

          isSessionLocal = true;

      }

      IDbCommand cmd = GetDbCommand(sqlMapper, statementName, paramObject, dictParam, dictParamDirection, CommandType.StoredProcedure); //存储过程

      try

      {

          cmd.Connection = session.Connection;

          IDbDataAdapter adapter = session.CreateDataAdapter(cmd);

          adapter.Fill(ds);

      }

      finally

      {

          if (isSessionLocal)

          {

              session.CloseConnection();

          }

      }

      htOutPutParameter = new Hashtable();

      foreach (IDataParameter parameter in cmd.Parameters)

      {

          if (parameter.Direction == ParameterDirection.Output)

          {

              htOutPutParameter[parameter.ParameterName] = parameter.Value;

          }

      }

      return ds.Tables[0];

  }

测试的存储过程如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

USE [TestDb]

GO

--根据id查询某人 并返回所有人中,最大体重,最小身高

CREATE    PROCEDURE [dbo].[usp_GetPersonById]

    @MaxWeight float output,

    @MinHeight float output,

    @Id int

AS

BEGIN

SELECT

    Id,

    FirstName,

    LastName,

    Weight,

    Height

FROM

    Person

    WHERE [email protected]

    

SET @MaxWeight= (SELECT MAX(Weight) FROM Person)

SET @MinHeight= (SELECT MIN(Height) FROM Person)

END

本文的示例测试通过,返回的结果如下:

从上图中,我们可以看到最大体重是200,最矮身高是177。

4、小结和注意点

a、返回ADO.NET对象的方法,iBatis拼接的SQL语句必须通过而不是熟悉的#符号连接,这个会有众所周知的SQL注入的风险。

b、我还没有实际尝试过最新版本的iBatis,对于较新的版本,不知道本文的方法还适不适用。

c、我参考这篇文章的时候,发现说有一个无法返回output参数的问题。我尝试着重现这个问题。功夫不负有心人,本文示例中我已经实现好了,给自己鼓励一下。

时间: 2024-10-20 05:00:45

iBatis.Net实现返回DataTable和DataSet对象的相关文章

LINQ返回DataTable类型 list转dataset 转换为JSON对象

using System.Web.Script.Serialization; using System.Collections.Generic; using System.Reflection; using System.Data; using System; namespace CommonCode { public class Common { /// <summary> /// LINQ返回DataTable类型 /// </summary> public static Da

C# 实现DataTable、DataSet与XML互相转换

/**//// <summary> /// 把DataSet.DataTable.DataView格式转换成XML字符串.XML文件 /// </summary> public class DataToXml { /**//// <summary> /// 将DataTable对象转换成XML字符串 /// </summary> /// <param name="dt">DataTable对象</param> //

C#与数据库访问技术总结(十六)之 DataSet对象

DataSet对象 DataSet对象可以用来存储从数据库查询到的数据结果,由于它在获得数据或更新数据后立即与数据库断开,所以程序员能用此高效地访问和操作数据库. 并且,由于DataSet对象具有离线访问数据库的特性,所以它更能用来接收海量的数据信息. DataSet对象概述 DataSet是ADO.NET中用来访问数据库的对象. 由于其在访问数据库前不知道数据库里表的结构,所以在其内部,用动态XML的格式来存放数据.这种设计使DataSet能访问不同数据源的数据. DataSet对象本身不同数

浅谈ASP.net中的DataSet对象

在我们对数据库进行操作的时候,总是先把数据从数据库取出来,然后放到一个"容器"中,再通过这个"容器"取出数据显示在前台,而充当这种容器的角色中当属DataSet是最为普遍和重要的了,可以说DataSet在数据库和前台中起到了一个桥梁的作用. 下面就来谈谈DataSet的用法.(DataSet对象本身是没有存取数据库的能力的,它要与DataAdapter一般是配合使用的,而关于DataAdapter的用法在我的另一篇文章中有介绍,大家可以看一下) DataSet可以包

DataSet对象及使用

DataSet对象的概念: DataSet对象可以视为一个(Catch),它可以吧从数据库中所查到的数据保留下来,甚至可以将整个数据库暂存起来 DataSet是数据在内存中的表示形式 DataSet对象和数据源的联机发生的很短暂,我们在取得数据后就立即和数据源断开了,等到数据修改完毕或是要操作数据源内的数据时才会再建立连接 DataSet对象包含一组DataTable对象和DataRelation对象 DataTable对象及使用 DataTable对象是DataSet的重要对象之一,表示内存中

C#之数据集:DataSet对象

ADO.NET数据访问技术的一个突出的特点就是支持离线访问,而实现这种离线访问技术的核心就是DataSet对象,该对象通过将数据驻留在内存来实现离线访问. DataSet对象概述 DataSet对象由一组DataTable对象组成,这些对象与DataRelation对象互相关联.这些DataSet对象又包含Rows集合,Columns集合,Rows集合由多个DataRow对象组成,Columns集合由多个DataColumn对象组成. 由于DataSet对象很像数据库,所以可以像访问关系型数据库

将Json数据转换为ADO.NET DataSet对象

Json数据转换为ADO.NET DataSet其实方法有很多,Newtonsoft.Json也提供了DataSet的Converter用以转换Json数据.但是有些情况下DataSet Converter并不管用,而且也不一定能够满足项目需要.这里介绍另一种简单有效的方法,能够方便快速地将Json数据转为ADO.NET DataSet. 设计 事实上Newtonsoft.Json已经提供了一套完整的Json数据文档结构,Newtonsoft.Json.Linq命名空间下提供了这种文档结构的对象

DataTable与DTO对象的简易转换类

在web开发过程中,有时候为了数据传输的方便,比如:后台需要更新前端的ViewModel,此时我们定义一个与前端ViewModel结构一样的DTO对象,从数据层获取数据后,将数据封装成DTO然后序列化为json传回前端,由于我正在开发的项目中的Model是用DataSet来实现的,不是纯粹的面向对象(如果Model是对象的话可以用AutoMapper来实现转换),所以从数据层获取的都是DataSet或DataTable,这时需要将DataTable转换为DTO对象,DTO对象的属性与DataTa

WebService返回DataTable问题

今天做项目时,想在WebService中返回DataTable,在单位没成功,看网上有人说datable在.net1.1中是没有序列化的,不能直接在webservice中返回,可以返回dataset.晚上回家又上网找了一下,看到说法基本一致,还有一篇被引用很多的文章说在asp.net2.0中datatable已经被序列化了,但是还需要自己手动写一些代码才能从webservice中返回.我就想一定要写另写代码吗?继续查找,发现有人说必须给datable起名就可以返回了,还可以在调用端手动转换为da