iBATIS.net获取运行时sql语句

  【本文原创,第一次离首页如此之近。发在候选区攒攒rp,管理员看着不合适可以撤下。】

  虽然只在iBatis的世界里小打小闹匆匆数月,却历经数次与领导和同事激辩,再通过不懈努力学习和开发积累,楼猪终于被它小巧而不失强大,稳定而不失灵活所折服。作为80后顽固、偏执和nc一族,楼猪一向保守认为自己是美貌与智慧并存的。仗着天资聪慧,在之前的“ iBatis.net直接执行sql语句”里曾经公然抱怨iBATIS对sql语句的直接查看灰常的不友好,调试不方便,排除错误非常考验眼神,很重要的一条(甚至应该算是楼猪一开始就讨厌排斥iBatis的罪魁祸首)就是参数化的sql语句。但是也不能说获取到的运行时sql语句一点用木有,至少我们还是可以看到sql语句的大致组装情况的。说到这里,再对照标题,您可能会认为楼猪是要教大家怎么获取运行时的sql语句。以楼猪一贯自恋臭美的作风,这次会这么肤浅么......
  再给大家一次大胆猜测的机会......当当当当,我kao,新年新气象,大家变得更聪明了,一点惊喜和意外都木有,果然。好了,有没有新意,看看楼猪的介绍再说吧:

一、常见iBatis.net获取运行时sql语句方式
通常我们都是在一个公共类里写一个方法,单独作为获取sql语句的帮助类(IBatisHelper.cs),然后在sqlmapper方法调用的地方调用帮助类和它的方法。
1、实现代码
代码
         ///   <summary>
        
///  得到运行时ibatis.net动态生成的SQL
        
///   </summary>
        
///   <param name="sqlMapper"></param>
        
///   <param name="statementName"></param>
        
///   <param name="paramObject"></param>
        
///   <returns></returns>
         public static   string  GetRuntimeSql(ISqlMapper sqlMapper,  string  statementName,  object  paramObject)
        {
            
string  result  =   string .Empty;
            
try
            {
                IMappedStatement statement 
=  sqlMapper.GetMappedStatement(statementName);
                
if  ( ! sqlMapper.IsSessionStarted)
                {
                    sqlMapper.OpenConnection();
                }
                RequestScope scope 
=  statement.Statement.Sql.GetRequestScope(statement, paramObject, sqlMapper.LocalSession);
                result 
=  scope.PreparedStatement.PreparedSql;
            }
            
catch  (Exception ex)
            {
                result 
=   " 获取SQL语句出现异常: "   +  ex.Message;
            }
            
return  result;
        }

 2、使用帮助类获取sql语句
接着采用类似如下实现方式进行调用:

代码
        public  IList < Person >  SelectPersons(Person model)
        {
            
string  sql  =  IBatisHelper.GetRuntimeSql( this .SqlMapper,  this .GetStatementName( " SelectPersons " ), model);
            
return   this .SqlMapper.QueryForList < Person > ( this .GetStatementName( " SelectPersons " ), model);
        }

在之前做过的大大小小形形色色的项目中,楼猪没少这么写,开发团队其他成员也是一样的,灰常和谐默契。

二、iBatis.net获取运行时sql语句方式的改进
  但是每做一个新项目就要写个一模一样的帮助类来(嗨,您现在嗅到坏味道并且看到杯具了吧?!),偏执追求完美的nc楼猪就想,各位大神早就教导我们重复是邪恶的(Duplication is Evil (DIE)),大家一起不亦乐乎地重复呢?这里您一定会善意建议楼猪把帮助类写进公共类库里,大家以后公共调用那个类库就可以了。思路确实没错,很不客气地说,楼猪第一次使用iBatis就想这么干了。看到这里含蓄的您可能已经会心一笑,豪放点的也许已经也有“tmd,老子也和你想到一块去了”之感。其实在很多技术问题上,大家的看法最终还是非常容易达到高度统一的。
  楼猪是通过抽象出一个具有获取运行时sql语句的方法的BaseIBatisDao基类,封装并改进初始化SqlMapper对象的方式实现公共调用的:
1、BaseIBatisDao泛型抽象类

代码
using  System;
using  IBatisNet.DataMapper;
using  IBatisNet.DataMapper.Scope;
using  IBatisNet.DataMapper.MappedStatements;

namespace  DotNet.Common.IBatisUtil
{
    
public   abstract   class  BaseIBatisDao < T >   where  T :  class
    {
        
#region  Properties

        
public  ISqlMapper SqlMapper {  get set ; }

        
#endregion

        
#region  Constructor

        
public  BaseIBatisDao()
        {
        }

        
public  BaseIBatisDao( string  mapperName)
        {
            
this .SqlMapper  =  SqlMapperManager.GetMapper(mapperName);
        }

        
#endregion

        
#region  Functions

        
///   <summary>
        
///  得到运行时ibatis.net动态生成的SQL
        
///   </summary>
        
///   <param name="sqlMapper"></param>
        
///   <param name="statementName"></param>
        
///   <param name="paramObject"></param>
        
///   <returns></returns>
         public   virtual   string  GetRuntimeSql(ISqlMapper sqlMapper,  string  statementName,  object  paramObject)
        {
            
string  result  =   string .Empty;
            
try
            {
                IMappedStatement statement 
=  sqlMapper.GetMappedStatement(statementName);
                
if  ( ! sqlMapper.IsSessionStarted)
                {
                    sqlMapper.OpenConnection();
                }
                RequestScope scope 
=  statement.Statement.Sql.GetRequestScope(statement, paramObject, sqlMapper.LocalSession);
                result 
=  scope.PreparedStatement.PreparedSql;
            }
            
catch  (Exception ex)
            {
                result 
=   " 获取SQL语句出现异常: "   +  ex.Message;
            }
            
return  result;
        }

        
///   <summary>
        
///  获取sqlMap对应statement的完整id
        
///   </summary>
        
///   <param name="name"></param>
        
///   <returns></returns>
         protected   virtual   string  GetStatementName( string  name)
        {
            
return   string .Format( " {0}.{1} " typeof (T).Namespace, name);
        }

        
#endregion

    }
}

 在这个基类中,在初始化SqlMapper对象的地方,楼猪是通过一个辅助类(SqlMapperManager)通过单例模式实现的:

代码
using  System;
using  System.Collections.Generic;
using  IBatisNet.DataMapper;
using  IBatisNet.DataMapper.Configuration;
using  IBatisNet.DataMapper.SessionStore;

namespace  DotNet.Common.IBatisUtil
{
    
///   <summary>
    
///  SqlMap创建管理
    
///   </summary>
     public   class  SqlMapperManager
    {
        
private   static   readonly   object  objSync  =   new   object ();
        
private   static   readonly  IDictionary < string , ISqlMapper >  dictMappers  =   null ;

        
static  SqlMapperManager()
        {
            dictMappers 
=   new  Dictionary < string , ISqlMapper > ();
        }

        
///   <summary>
        
///  实例化SqlMap对象
        
///   </summary>
        
///   <param name="mapperName"> 通常.config文件 </param>
        
///   <returns></returns>
         public   static  ISqlMapper GetMapper( string  mapperName)
        {
            
if  ( string .IsNullOrEmpty(mapperName))
            {
                
throw   new  Exception( " MapperName为空! " );
            }
            
if  (mapperName.ToLower().LastIndexOf( " .config " ==   - 1 )
            {
                mapperName 
+=   " .config " ;
            }
            ISqlMapper mapper 
=   null ;
            
if  (dictMappers.ContainsKey(mapperName))
            {
                mapper 
=  dictMappers[mapperName];
            }
            
else
            {
                
if  (mapper  ==   null )
                {
                    
lock  (objSync)
                    {
                        
if  (mapper  ==   null )
                        {
                            mapper 
=   new  DomSqlMapBuilder().Configure(mapperName);
                            mapper.SessionStore 
=   new  HybridWebThreadSessionStore(mapper.Id);
                            dictMappers.Add(mapperName, mapper);
                        }
                    }
                }
            }
            
return  mapper;
        }
    }
}

 2、在DAO中调用BaseIBatisDao基类

代码
using  System.Collections.Generic;
using  DotNet.Common.IBatisUtil;
using  IBatisNetApp.DAL.Model;

namespace  IBatisNetApp.DAL.DAO
{
    
public   class  PersonDao : BaseIBatisDao < Person >
    {
        
public  PersonDao()
            : 
base ( " Query.config " )
        {
        }

        
public  IList < Person >  SelectPersons(Person model)
        {
            
string  sql  =   this .GetRuntimeSql( this .SqlMapper,  this .GetStatementName( " SelectPersons " ), model);
            
return   this .SqlMapper.QueryForList < Person > ( this .GetStatementName( " SelectPersons " ), model);
        }

        
public  IDictionary < int , Person >  SelectDictStoreInfo(Person model)
        {
            
string  sql  =   this .GetRuntimeSql( this .SqlMapper,  this .GetStatementName( " SelectPersons " ), model);
            
return   this .SqlMapper.QueryForDictionary < int , Person > ( this .GetStatementName( " SelectPersons " ), model,  " Id " );
        }

        
public  IList < Person >  SelectPagerPersons(Person model)
        {
            
string  sql  =   this .GetRuntimeSql( this .SqlMapper,  this .GetStatementName( " SelectPagerPersons " ), model);
            
return   this .SqlMapper.QueryForList < Person > ( this .GetStatementName( " SelectPagerPersons " ), model);
        }

        
public   int  InsertPerson(Person model)
        {
            
string  sql  =   this .GetRuntimeSql( this .SqlMapper,  this .GetStatementName( " InsertPerson " ), model);
            
int  result  =   0 ;
            
object  obj  =   this .SqlMapper.Insert( this .GetStatementName( " InsertPerson " ), model);
            
if  (obj  !=   null )
            {
                result 
=   int .Parse(obj.ToString());
            }
            
return  result;
        }

        
public   int  DeletePersonById( int  id)
        {
            
string  sql  =   this .GetRuntimeSql( this .SqlMapper,  this .GetStatementName( " DeletePersonById " ), id);
            
int  result  =   0 ;
            
object  obj  =   this .SqlMapper.Delete( this .GetStatementName( " DeletePersonById " ), id);
            
if  (obj  !=   null )
            {
                result 
=   int .Parse(obj.ToString());
            }
            
return  result;
        }

        
public   int  UpdatePersonById(Person model)
        {
            
string  sql  =   this .GetRuntimeSql( this .SqlMapper,  this .GetStatementName( " UpdatePersonById " ), model);
            
int  result  =   0 ;
            
object  obj  =   this .SqlMapper.Update( this .GetStatementName( " UpdatePersonById " ), model);
            
if  (obj  !=   null )
            {
                result 
=   int .Parse(obj.ToString());
            }
            
return  result;
        }
    }
}

 如您所看到的那样,在每一个方法里,我们要获取运行时sql语句,只要用this来get一下就可以了,看上去这个方法就像是ibatis直接封装好提供给我们的一样,再对照之前的方式,强弱悬殊,高下立判。这里要特别说明,获取运行时sql语句通常都是开发者调试时的一种辅助。调试成功后,您可以及时把获取sql的那一行注释掉。有了这个方法,普通开发调试就比较圆满了(您还可以按照项目需要扩展出其他方法,比如通过datatable,datareader等等获取sql语句),而且调用灰常省事。
3、关于DAL层的几句废话
a、在本文最下面,楼猪会给出demo下载链接。之前的几篇介绍总结iBatis的文章里,iBatis的类库版本较低(1.3.0.0),现在已经升级到(1.6.1.0),开发环境Vs2008+Sql  Server2005 Express.在运行程序的时候,请先在Sql Server上执行Script文件夹下的sql脚步建数据库和对应的表。要下载学习的童鞋请注意。
b、model层的说明
Person类直接继承的第一个基类(BaseModel)存的是其他表也可能用到的公共字段(主键Id);BaseModel直接继承自用于作为扩展查询条件的BaseQuery类;BaseQuery类继承自支持with方式分页的PagerBase类。其实看命名您可以猜到它们的各自作用了。不同的实体类可以按需要继承这三个类。
c、with分页查询方式
这个是sql server2005的with和公用表表达式提供的功能,分页效率和效果都很不错,dao所对应的xml文件里用到了“iBATIS.net复用sql语句片段”功能。sql server2005前版本和非sql server的数据库不支持此方式。楼猪之前都是通过更通用的二次top方式进行分页,希望您留意。

最后ps,本来计划在本文把iBatis事务和它的自带分页功能一并介绍的,一想起曾经无比挫折的事务使用经历,兴致全无。低俗的一句结束:日后再说。

demo下载:IBatisApp

你可能感兴趣的:(ibatis)