如题。要返回一个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 Id=@Id
     
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参数的问题。我尝试着重现这个问题。功夫不负有心人,本文示例中我已经实现好了,给自己鼓励一下。

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

  1. IBatis.Net使用总结(二)-- IBatis返回DataTable/DataSet(网上例子的集合)

    IBatis返回DataTable,DataSet ibatis.net QueryForDataTable 完整的为ibatis.net 引入datatable支持要改动很多地方,所以描述的是最小化 ...

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

    using System.Web.Script.Serialization; using System.Collections.Generic; using System.Reflection; us ...

  3. IBatis.Net使用总结(三)-- IBatis实现分页返回数据和总数

    IBatis 分页,这里没有使用其他插件,只使用最原始的方法. 输入参数: int currentPage 当前页 int  pageSize 每页大小 Hashtable findCondition ...

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

    DataSet对象 DataSet对象可以用来存储从数据库查询到的数据结果,由于它在获得数据或更新数据后立即与数据库断开,所以程序员能用此高效地访问和操作数据库. 并且,由于DataSet对象具有离线 ...

  5. 浅谈ASP.net中的DataSet对象

    在我们对数据库进行操作的时候,总是先把数据从数据库取出来,然后放到一个"容器"中,再通过这个"容器"取出数据显示在前台,而充当这种容器的角色中当属DataSet ...

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

    /**//// <summary> /// 把DataSet.DataTable.DataView格式转换成XML字符串.XML文件 /// </summary> public ...

  7. DataTable与DTO对象的简易转换类

    在web开发过程中,有时候为了数据传输的方便,比如:后台需要更新前端的ViewModel,此时我们定义一个与前端ViewModel结构一样的DTO对象,从数据层获取数据后,将数据封装成DTO然后序列化 ...

  8. .Net中List<T> 泛型转成DataTable、DataSet

    在开发过程过程中有时候需要将List<T>泛型转换成DataTable.DataSet,可以利用反射机制将DataTable的字段与自定义类型的公开属性互相赋值. 1.List<T& ...

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

    Json数据转换为ADO.NET DataSet其实方法有很多,Newtonsoft.Json也提供了DataSet的Converter用以转换Json数据.但是有些情况下DataSet Conver ...

随机推荐

  1. 【读书笔记】iOS-NSPredicate

    一,Cocoa提供了一个名为NSPredicate的类,它用于指定过滤器的条件.可以创建NSPredicate对象,通过该对象准确地描述所需的条件,对每个对象通过谓词进行筛选,判断它们是否与条件相匹配 ...

  2. js地理位置获取、显示、轨迹绘制

    JS新API标准 地理定位(navigator.geolocation) 基于 html5 geolocation来获取经纬度地址 Html5 Geolocation获取地理位置信息 HTML5获取地 ...

  3. svn conflict

    安装svn apt-get install subversion 当前两个人都更新版本为version1 A修改了monitor.txt文件 提交后版本为version2 B也修改了monitor.t ...

  4. Effective Java 21 Use function objects to represent strategies

    Theory In the Java the function pointers is implemented by the declaring an interface to represent s ...

  5. Effective Java 60 Favor the use of standard exceptions

    Benefits to reuse preexisting exceptions It makes your API easier to learn and use. Programs using y ...

  6. android SQLiteOpenHelper使用示例

    我们大家都知道Android平台提供给我们一个数据库辅助类来创建或打开数据库,这个辅助类继承自SQLiteOpenHelper类,在该类的 构造器中,调用Context中的方法创建并打开一个指定名称的 ...

  7. 详解apache的allow和deny

    今天看了一篇关于apache allow,deny的文章收获匪浅,防止被删,我直接摘过来了,原文地址!!! !http://www.cnblogs.com/top5/archive/2009/09/2 ...

  8. NOIP2008 T3 传纸条 解题报告——S.B.S.

    题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...

  9. docker containerd中的容器操作

    containerd的中的各种操作都是通过Task来进行的,因此对于容器的create, start, delete等等操作其实都是一个个的Task而已. Task的数据结构如下所示: type Ta ...

  10. 离散化+线段树 POJ 3277 City Horizon

    POJ 3277 City Horizon Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 18466 Accepted: 507 ...