1. 程式人生 > >iBATIS.net獲取執行時sql語句

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

轉載自:http://www.cnblogs.com/jeffwongishandsome/archive/2010/02/24/1672960.html