IBatis返回DataTable,DataSet
ibatis.net QueryForDataTable
完整的为ibatis.net 引入datatable支持要改动很多地方,所以描述的是最小化的改动.不过我们可以大概了解一下比较完整的集成要做那些事情.
ibatis.net 的基本运行原理就是获得一个reader后,然后进行循环,对每条记录使用ResultStrategy中的对应实现进行处理,然后返回到结果集.因此,首先,需要实现一个DataTableStrategy 用来为每条记录产生一个新DataRow. 大家可以看到,下面的实现已经绕开了ibatis.net的处理逻辑.
你可以在网上google到一些ibatis返回dataset的代码,可在最新的版本1.6 ibatis.net 这些代码都无法工作,这是因为RequestScope.IDbCommand现在返回的是一个DbCommandDecorator对象实例(一个实现IDbCommand接口并代理一个具体的IDbCommand实现的对象),而DataAdapter的实现,需要对应的idbcommand实现,如 SqlDataAdapter需要SqlCommand.因此,如下代码会导致cast错误
Mapper.LocalSession.CreateDataAdapter(scope.IDbCommand).Fill(dataTable);
这里有两种解法,一是使用datatable.Load方法来装载IDbCommand.ExecuteReader的返回结果,这是可行的
其次是利用反射,实际的idbcommand在DbCommandDecorator中被保存为_innerDbCommand field ,下面是两种实现. 大约的感觉,如果你在意性能的话,第一种会快些
1 /// <summary> 2 /// 查询返回DatatTable 3 /// </summary> 4 /// <param name="statementName"></param> 5 /// <param name="parameterObject"></param> 6 /// <returns></returns> 7 public DataTable QueryForDataTable(string statementName, object parameterObject) 8 { 9 bool isSessionLocal = false; 10 ISqlMapSession session = SqlMap.LocalSession; 11 DataTable dataTable = null; 12 if (session == null) 13 { 14 session = SqlMap.CreateSqlMapSession(); 15 isSessionLocal = true; 16 } 17 try 18 { 19 IMappedStatement statement = SqlMap.GetMappedStatement(statementName); 20 dataTable = new DataTable(statementName); 21 RequestScope request = statement.Statement.Sql.GetRequestScope(statement, parameterObject, session); 22 statement.PreparedCommand.Create(request, session, statement.Statement, parameterObject); 23 using (request.IDbCommand) 24 { 25 dataTable.Load(request.IDbCommand.ExecuteReader()); 26 } 27 } 28 catch 29 { 30 throw; 31 } 32 finally 33 { 34 if (isSessionLocal) 35 { 36 session.CloseConnection(); 37 } 38 } 39 return dataTable; 40 }