如题。要返回一个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. 【原/转】opencv的级联分类器训练与分类全程记录

    众所周知,opencv下有自带的供人脸识别以及行人检测的分类器,也就是说已经有现成的xml文件供你用.如果我们不做人脸识别或者行人检测,而是想做点其他的目标检测该怎么做呢?答案自然是自己训练一个特定的 ...

  2. iOS 视频选择压缩

    //原理,还是调用UIImagePickerController控制器,设置Type为视频 #import "ViewController.h" #import <AVFou ...

  3. SQL Server 2008 R2——VC++ ADO 操作 参数化查询

    ==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...

  4. Solr 参考资料

    solr 的入门好资料 https://cwiki.apache.org/confluence/display/solr/Apache+Solr+Reference+Guide https://two ...

  5. jQuery form插件的使用--处理server返回的JSON, XML,HTML数据

    详细代码: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> & ...

  6. html不使用cache数据

    <HEAD>      <META   HTTP-EQUIV="Pragma"   CONTENT="no-cache">     &l ...

  7. jQuery选择器简单例子

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="jQuery_5.aspx. ...

  8. python Quicksort demo

    __author__ = 'student' ''' quicksort step 1, choose one pivot, such as pivot=la[0] step 2, scan the ...

  9. 拓扑排序 codevs 4040 cojs 438

    codevs 4040 EZ系列之奖金  时间限制: 1 s  空间限制: 64000 KB  题目等级 : 钻石 Diamond 题目描述 Description 由于无敌的WRN在2015年世界英 ...

  10. 孙鑫视频学习:关于Visual Studio 2010中MFC工程的消息WM_INITDIALOG找不到的问题

    学习孙鑫的那个深入详解C++视频时,有一处给编辑框空间改写窗口过程函数的例子,其中需要添加一个WM_INITDIALOG消息响应函数,但在类向导的消息栏下找不到WM_INITDIALOG消息.解决方法 ...