Thursday, February 25, 2010

IBatis.NET in Action

Seeing Ibatis action in the JPetstore make me wonder if there is similar framework is available in .NET platform. A fellow in JUG Indonesia also claimed that Ibatis increase his productivity in project's development. Now there is a good news, Ibatis is available in .NET as Ibatis.NET. Below are my POC of IBatis.NET

The interface: IReferenceCodeDao.cs
using System;
using System.Collections;
using System.Text;

using Dallanube.VIP.Cafestol.Model.Setup;

namespace Dallanube.VIP.Cafestol.Dao.Factory.Setup
{
    public interface IReferenceCodeDao
    {
        IList GetReferenceCodesByCriteria(ReferenceCode code);
        ReferenceCode GetReferenceCode(ReferenceCode code);
        String GetReferenceCodeDescription(ReferenceCode code);
        Object AddReferenceCode(ReferenceCode code);
        int UpdateReferenceCode(ReferenceCode code);
        int DeleteReferenceCode(ReferenceCode code);
        IList GetReferenceCategoryByCriteria(ReferenceCode code);
        ReferenceCode GetReferenceCategory(ReferenceCode code);        
    }
}

DAO implementation: ReferenceCodeDao.cs
using System;
using System.Collections;
using System.Text;

using Dallanube.Caffeine.Dao.Persistence;
using Dallanube.VIP.Cafestol.Model.Setup;
using Dallanube.VIP.Cafestol.Dao.Factory.Setup;

namespace Dallanube.VIP.Cafestol.Dao.Persistence.Setup
{
    public class ReferenceCodeDao : BasePersistenceDao, IReferenceCodeDao
    {
        public IList GetReferenceCodesByCriteria(ReferenceCode code)
        {
            return ExecuteQueryForList("GetReferenceCodesByCriteria", code);
        }

        public ReferenceCode GetReferenceCode(ReferenceCode code)
        {
            return (ReferenceCode)ExecuteQueryForObject("GetReferenceCode", code);
        }

        public String GetReferenceCodeDescription(ReferenceCode code)
        {
            return Convert.ToString(ExecuteQueryForObject("GetReferenceCodeDescription", code));
        }

        public Object AddReferenceCode(ReferenceCode code)
        {
            return ExecuteInsert("AddReferenceCode", code);
        }

        public int UpdateReferenceCode(ReferenceCode code)
        {
            return ExecuteUpdate("UpdateReferenceCode", code);
        }

        public int DeleteReferenceCode(ReferenceCode code)
        {
            return ExecuteUpdate("DeleteReferenceCode", code);
        }

        public IList GetReferenceCategoryByCriteria(ReferenceCode code)
        {
            return ExecuteQueryForList("GetReferenceCategory", code);
        }

        public ReferenceCode GetReferenceCategory(ReferenceCode code)
        {
            return (ReferenceCode)ExecuteQueryForObject("GetReferenceCategory", code);
        }
    }
}
XML Mapping: ReferenceCode.xml

<?xml version="1.0" encoding="UTF-8" ?>
<sqlMap namespace="ReferenceCode"
xmlns="http://ibatis.apache.org/mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >

  <alias>
    <typeAlias alias="ReferenceCode" type="Dallanube.VIP.Cafestol.Model.Setup.ReferenceCode, Dallanube.VIP.Cafestol.Core" />
    <typeAlias alias="ReferenceCategory" type="Dallanube.VIP.Cafestol.Model.Setup.ReferenceCategory, Dallanube.VIP.Cafestol.Core" />
  </alias>

  <resultMaps>
    <resultMap id="ReferenceCodeResult" class="ReferenceCode">
      <result property="Category" column="CATEGORY"/>
      <result property="Code" column="CODE"/>
      <result property="Description" column="DESCRIPTION"/>
      <result property="MapCode" column="MAP_CODE"/>
    </resultMap>
    <resultMap id="ReferenceCategoryResult" class="ReferenceCategory">
      <result property="Category" column="CATEGORY"/>
      <result property="Description" column="DESCRIPTION"/>
      <result property="Int01" column="INT01"/>
    </resultMap>
    </resultMaps>
  <!-- =============================================
        MAPPED STATEMENTS 
    ============================================= 
    -->
  <statements>
    <select id="GetReferenceCodesByCriteria" resultMap="ReferenceCodeResult">
      select
      CATEGORY,
      CODE,
      DESCRIPTION,
      MAP_CODE
      from REF_CODE
      <dynamic prepend="WHERE">
        <isNotEmpty prepend="AND" property="Category">
          CATEGORY = #Category#
        </isNotEmpty>
        <isNotEmpty prepend="AND" property="Code">
          CODE like '$Code$%'
        </isNotEmpty>
        <isNotEmpty prepend="AND" property="Description">
          DESCRIPTION like '%$Description$%'
        </isNotEmpty>
        <isNotEmpty prepend="AND" property="IsTitle">
          IS_TITLE = #IsTitle#
        </isNotEmpty>
      </dynamic>
    </select>

    <select id="GetReferenceCode" resultMap="ReferenceCodeResult">
        select
        CATEGORY,
        CODE,
        DESCRIPTION,
        MAP_CODE
        from REF_CODE
        WHERE CATEGORY = #Category#
        and CODE = #Code#
    </select>

    <select id="GetReferenceCodeDescription" resultClass="String">
      select DESCRIPTION from REF_CODE
      where CATEGORY = #Category#
      and CODE = #Code#
      and IS_TITLE = #IsTitle#
    </select>
    
    <select id="GetReferenceCategory" resultMap="ReferenceCategoryResult">
      select code1.CATEGORY, code2.CODE, code1.INT01, code2.DESCRIPTION
      from (
      select category, count(code) int01 from REF_CODE
      group by category
      ) as code1
      left join REF_CODE code2
      on code1.CATEGORY = code2.CATEGORY
      and code2.IS_TITLE = 1
      <dynamic prepend="WHERE">
        <isNotEmpty prepend="AND" property="Category">
          code1.CATEGORY = #Category#
        </isNotEmpty>
        <isNotEmpty prepend="AND" property="Description">
          code2.DESCRIPTION like '%$Description$%'
        </isNotEmpty>
      </dynamic>
    </select>
    
    <insert id="AddReferenceCode" parameterClass="ReferenceCode">
      insert into REF_CODE
      (CATEGORY, CODE, DESCRIPTION, IS_TITLE, MAP_CODE)
      values
      (#Category#, #Code#, #Description#, #IsTitle#, #MapCode#)
    </insert>

    <update id="UpdateReferenceCode" parameterClass="ReferenceCode">
      update REF_CODE set
      DESCRIPTION = #Description#,
      MAP_CODE = #MapCode#
      where CATEGORY = #Category#
      and CODE  = #Code#
      and IS_TITLE = #IsTitle#
    </update>
    
    <update id="DeleteReferenceCode" parameterClass="ReferenceCode">
      delete from REF_CODE
      <dynamic prepend="WHERE">
        <isNotEmpty prepend="AND" property="Category">
          CATEGORY = #Category#
        </isNotEmpty>
        <isNotEmpty prepend="AND" property="Code">
          CODE = #Code#
        </isNotEmpty>
        <isNotEmpty prepend="AND" property="IsTitle">
          IS_TITLE = #IsTitle#
        </isNotEmpty>
      </dynamic>
    </update>
  </statements>

</sqlMap>
Base class for Dao, all DAO class inherit from this: BasePersistenceDao.cs
using System;
using System.Collections;
using System.Data;
using System.Runtime.Serialization;
using System.Text;

using IBatisNet.Common.Exceptions;
using IBatisNet.Common.Pagination;
using IBatisNet.DataAccess;
using IBatisNet.DataAccess.Interfaces;
using IBatisNet.DataAccess.DaoSessionHandlers;
using IBatisNet.DataMapper;

namespace Dallanube.Caffeine.Dao.Persistence
{ 
 ///
 ///   Desson Ariawan
 /// 
 public class BasePersistenceDao: IDao
 {
        protected const int PAGE_SIZE = 4;
        private ISqlMapper localSqlMap;

        protected String tableName;
        public String TableName
        {
            get
            {
                return tableName;
            }
            set
            {
                tableName = value;
            }
        }
        ///         /// Looks up the parent DaoManager, gets the local transaction
        /// (which should be a SqlMapDaoTransaction) and returns the
        /// SqlMap associated with this DAO.
        ///         /// The SqlMap instance for this DAO.
        protected ISqlMapper GetLocalSqlMap()
        {
            if (localSqlMap == null)
            {
                IDaoManager daoManager = DaoManager.GetInstance(this);
                SqlMapDaoSession sqlMapDaoSession = (SqlMapDaoSession)daoManager.LocalDaoSession;

                localSqlMap = sqlMapDaoSession.SqlMap;
            }
            return localSqlMap;
        }

        ///         /// Simple convenience method to wrap the SqlMap method of the same name.
        /// Wraps the exception with a IBatisNetException to isolate the SqlMap framework.
        /// 
        protected IList ExecuteQueryForList(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetLocalSqlMap();
            try
            {
                return sqlMap.QueryForList(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for list. Cause: " + e.Message, e);
            }
        }

        ///         /// Simple convenience method to wrap the SqlMap method of the same name.
        /// Wraps the exception with a IBatisNetException to isolate the SqlMap framework.
        /// 
        protected IList ExecuteQueryForList(string statementName, object parameterObject, int skipResults, int maxResults)
        {
            ISqlMapper sqlMap = GetLocalSqlMap();
            try
            {
                return sqlMap.QueryForList(statementName, parameterObject, skipResults, maxResults);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for list. Cause: " + e.Message, e);
            }
        }

        /////         ///// Simple convenience method to wrap the SqlMap method of the same name.
        ///// Wraps the exception with a IBatisNetException to isolate the SqlMap framework.
        ///// 
        //protected IPaginatedList ExecuteQueryForPaginatedList(string statementName, object parameterObject, int pageSize)
        //{
        //    ISqlMapper sqlMap = GetLocalSqlMap();
        //    try
        //    {
        //        return sqlMap.QueryForPaginatedList(statementName, parameterObject, pageSize);
        //    }
        //    catch (Exception e)
        //    {
        //        throw new IBatisNetException("Error executing query '" + statementName + "' for paginated list.  Cause: " + e.Message, e);
        //    }
        //}

        ///         /// Simple convenience method to wrap the SqlMap method of the same name.
        /// Wraps the exception with a IBatisNetException to isolate the SqlMap framework.
        /// 
        protected object ExecuteQueryForObject(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetLocalSqlMap();

            try
            {
                return sqlMap.QueryForObject(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for object. Cause: " + e.Message, e);
            }
        }

        ///         /// Simple convenience method to wrap the SqlMap method of the same name.
        /// Wraps the exception with a IBatisNetException to isolate the SqlMap framework.
        /// 
        protected int ExecuteUpdate(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetLocalSqlMap();

            try
            {
                return sqlMap.Update(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for update. Cause: " + e.Message, e);
            }
        }

        ///         /// Simple convenience method to wrap the SqlMap method of the same name.
        /// Wraps the exception with a IBatisNetException to isolate the SqlMap framework.
        /// 
        protected object ExecuteInsert(string statementName, object parameterObject)
        {
            ISqlMapper sqlMap = GetLocalSqlMap();

            try
            {
                return sqlMap.Insert(statementName, parameterObject);
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing query '" + statementName + "' for insert. Cause: " + e.Message, e);
            }
        }

        protected DataSet ExecuteQueryForDataSet(String statement)
        {
            ISqlMapper sqlMap = GetLocalSqlMap();
            try
            {
                IDbCommand objCmd = sqlMap.LocalSession.CreateCommand(CommandType.Text);
                objCmd.CommandText = statement;

                DataSet ds = new DataSet();
                IDbDataAdapter objDA = sqlMap.LocalSession.CreateDataAdapter();
                objDA.SelectCommand = objCmd;
                objDA.Fill(ds);

                return ds;
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing statement for DataSet. Cause: " + e.Message, e);
            }
        }

        protected IDataReader ExecuteQueryForDataReader(String statement)
        {
            ISqlMapper sqlMap = GetLocalSqlMap();
            try
            {
                IDbCommand objCmd = sqlMap.LocalSession.CreateCommand(CommandType.Text);
                objCmd.CommandText = statement;

                if (objCmd.Connection.State == ConnectionState.Closed)
                    objCmd.Connection.Open();

                IDataReader dr = objCmd.ExecuteReader();
                return dr;
            }
            catch (Exception e)
            {
                throw new IBatisNetException("Error executing statement for DataSet. Cause: " + e.Message, e);
            }
        }
 }
}
Pretty cool, heh? I'm using it in my Windows application with Spring.NET Reference: https://ibatisnet.sourceforge.net/Tutorial.html