Ibatisnet源码解读(2)—DataMapper

DataMapper是IbatisNet的核心,也是最复杂的部分。关于的工作原理或者说Ibatis的架构的简单描述如图所示:。
一.主要接口
1. IPreparedCommand 接口
     IPreparedCommand接口位于IBatisNet.DataMapper.Commands定义了void Create (RequestScope request, IDalSession session, IStatement statement, object parameterObject )协议,实现类将为IDalSession和当前的IStatement生成一个IDbCommand并填充适当的参数对象,然后放入RequestScope中。
2. ISql 接口
       ISql接口位于IBatisNet.DataMapper.Configuration.Sql提供了RequestScope GetRequestScope(object parameterObject, IDalSession session)协议,实现类将为当前的会话请求获取RequestScope,并且为DynamicSql/SimpleDynamicSql填充parameterObject。RequestScope代表一个请求范围内的所有的和mapped statement处理相关的数据,比如要执行的IDbCommand,当前的ResultMap和ParameterMap等。
3. ITypeHandler接口
     ITypeHandler接口主要用于在结果集和实际类型之间处理和转换。
4. IMappedStatement接口
       IMappedStatement接口定义了一个MappedStatement的行为。包括ExecuteInsert,ExecuteUpdate和ExecuteQuery等。
5. IStatement接口
       IStatement接口封装了Ibatis DataMap模型中的一个可执行的sql语句相关的属性,比如CacheModelName,ParameterClass,ResultMap,Sql等。
6. ISqlChild接口
       ISqlChild接口是一个标志接口。代表Sql的子元素。
 
二.关键类
1.Commands目录
    主要用于创建PreparedCommand包括DefaultPreparedCommand和EmbedParamsPreparedCommand。
2.Configuration目录
     维护Ibatis的xml配置文件和对象模型的映射,是SqlMap的模型层。
3.Exceptions目录
     包含一个DataMapperException 类,DataMapper模块运行过程产生的所有异常都被转换为DataMapperException异常。
4.MappedStatements目录
     该目录包含了MappedStatement的核心执行类。
5.Scope目录
     维护了配置,请求和错误相关信息的范围类。ConfigurationScope类维护了配置文件处理过程的状态;ErrorContext用于为创建有确切含义的错误信息维护状态;RequestScope保持整个MappedStatement的执行状态和信息。
6.TypeHandlers目录
     处理数据库类型和DotNet类型的转换。
7.主目录
     SqlMapSession 实现了 IDalSession,用于维护与SqlMap相关的数据访问层的会话信息。
     SqlMapper 一个Facade类,通过MappedStatement执行相应的数据库操作。
     Mapper 用于访问通过SqlMap.Config定义的缺省SqlMapper的单例类。
 
三.执行流程
     使用Ibatis的SqlMapper比较简单,最简单的一般需要四步:
     1.提供SqlMap.config配置文件,用于定义相关的数据源和sql映射。
     2.提供SqlMap的配置文件,定义sql映射。
     3.写相关的业务类,用于查询结果的映射,如果不需要查询,有时可以省略该步。
     4.调用框架执行。
     一个简单的例子:
 
SqlMap.config配置文件--SqlMap.config
<?xml version="1.0" encoding="utf-8"?>
<sqlMapConfig xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance
     xsi:noNamespaceSchemaLocation="SqlMapConfig.xsd">  
     <settings>
         <setting useStatementNamespaces="false"/>
         <setting cacheModelsEnabled="true"/>
     </settings>
 
     <providers>
     <provider
         name="oracle9.2"
         description="Oracle, Oracle provider V9.2.0.401"
         enabled="false"
         assemblyName="Oracle.DataAccess, Version=9.2.0.401, Culture=neutral, PublicKeyToken=89b483f429c47342"
         connectionClass="Oracle.DataAccess.Client.OracleConnection" 
         commandClass="Oracle.DataAccess.Client.OracleCommand"
         parameterClass="Oracle.DataAccess.Client.OracleParameter"
         parameterDbTypeClass="Oracle.DataAccess.Client.OracleDbType"
         parameterDbTypeProperty="OracleDbType"
         dataAdapterClass="Oracle.DataAccess.Client.OracleDataAdapter"
         commandBuilderClass="Oracle.DataAccess.Client.OracleCommandBuilder"
         usePositionalParameters = "false"
         useParameterPrefixInSql = "true"
         useParameterPrefixInParameter = "false"
         parameterPrefix=":" 
         useDeriveParameters="false"
     />
     </providers>
 
     <database>
         <provider name="oracle9.2"/>
         <dataSource name="ibatisDemo" connectionString="Data Source=DATA-89;Persist Security Info=True;User ID=data;password=data"/>
     </database>
     <sqlMaps>
         <sqlMap resource="product.xml"/>
     </sqlMaps>    
</sqlMapConfig>
 
SqlMap的配置文件--product.xml
<?xml version="1.0" encoding="UTF-8" ?>
<sqlMap namespace="Product" xmlns=" http://ibatis.apache.org/mapping
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance ">
 
     <alias>
         <typeAlias alias="Product" assembly="Product.dll" type="Domain.Product" />     
     </alias>
            
     <resultMaps>                                    
         
         <resultMap id="productResult" class="Product">
              <result property="Id" column="ID"/>
              <result property="PlatId" column="PLAT_ID"/>
              <result property="Org" column="create_org"/>
         </resultMap>
         
     </resultMaps>
     
     <!-- =============================================
        MAPPED STATEMENTS 
    ============================================= 
    -->
     <statements>  
         <select id="getProduct" parameterClass="Product",resultMap="productResult">
              select
              ID, PLAT_ID,CREATE_ORG
              from PRODUCT_TEMP  
              where ID = #Id#        
         </select>
         
         <update id="updateNews" parameterClass="Product">
              update PRODUCT_TEMP 
              set create_org=#Org#
              where ID = #Id#
         </update>     
     </statements> 
     
</sqlMap>
 
业务类--product.cs
using System;
using System.Collections.Generic;
using System.Text;
 
namespace Domain
{
     public class Product
     {
         private string _id, _platId, _org;
 
         public string Id
         {
              get { return _id; }
              set { _id = value; }
         }
 
         public string Org
         {
              get { return _org; }
              set { _org = value; }
         }
 
         public string PlatId
         {
              get { return _platId; }
              set { _platId = value; }
         }
     }
}
 
调用SqlMap执行
     class Program
     {
         public static void Main(string[] args)
         {
              //由于我们定义的sqlmap映射文件中的getProduct查询需要Product实例作为参数,并且使用Product的Id
              //首先实例化一个Product并设置其Id。
              Product p=new Product();
              p.Id = "FR20T0000003000000096426";
              //调用SqlMapper的QueryForObject方法通过在sqlmap中的getProductsql语句,查询数据库,并将结果集映射为Product对象
              p=(Product)Mapper.Instance().QueryForObject("getProduct", p);
              Console.WriteLine("{0}-{1}-{2}",p.Id, p.Org, p.PlatId);
              //修改Org属性
              p.Org = "orgid2";
              //通过updateNews sql,传入具体的Product实例,更新数据库。
              Mapper.Instance().Update("updateNews", p);
              //再次查询
              Product p1 = (Product)Mapper.Instance().QueryForObject("getProduct", p);
              Console.WriteLine("{0}-{1}-{2}", p1.Id, p1.Org, p1.PlatId);
         }
     }
     以上就是一个简单的实例,下面根据源代码简介其执行流程。
     Mapper.Instance()时,如果默认SqlMap已初始化则直接返回初始化的实例,如果没有初始化则通过DomSqlMapBuilder从配置文件中初始化SqlMap。在DomSqlMapBuilder主要通过xpath将xml配置文件映射为Ibatis DataMap模型。也就是说SqlMap.config文件的xml元素和DataMap的对象模型是对应的。处理SqlMap.config的过程中会处理sqlmap.config中,我们定义的映射文件,例如例中的product.xml:
     <sqlMaps>
         <sqlMap resource="product.xml"/>
     </sqlMaps>    
 
     SqlMapper构造成功后,下一步就是执行具体的在我们自己的sqlMap文件(product.xml)中定义的sql映射。例如public object QueryForObject(string statementName, object parameterObject)。该方法首先会按照statementName获取在解析product.xml文件过程中生成的MappedStatement实例,我们的例子中就是getProduct对应的select语句:
         <select id="getProduct" parameterClass="Product",resultMap="productResult">
              select
              ID, PLAT_ID,CREATE_ORG
              from PRODUCT_TEMP  
              where ID = #Id#        
         </select>
这个语句需要一个Product类型的参数,结果是一个resultMap--productResult,定义如下:
         <resultMap id="productResult" class="Product">
              <result property="Id" column="ID"/>
              <result property="PlatId" column="PLAT_ID"/>
              <result property="Org" column="create_org"/>
         </resultMap>。
     执行时,框架首先会获取当前的IDalSession,然后代理给具体的MappedStatement实例进行数据库操作,比如SelectMappedStatement。处理得过程首先会根据不同的语句类型(insert,select),和相关配置信息(参数类型,结果类型,sql语句本身等)进行参数邦定,然后通过ado.net进行数据库访问,如果需要返回结果,自动组装结果等过程,然后返回。执行的过程中还会有缓存管理,异常处理,事件触发和管理等,使用者可以不用了解细节。
总结:
     可以看出,Ibatis的SqlMapper使用还是相对简单的,要充分使用Ibatis的SqlMapper,最主要的是要掌握它的模型和配置,模型和配置是对应的。不掌握模型很难很好的编写配置文件。有时间会按专题介绍Ibatis配置中的重要模型。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IBatisNet.DataMapper 1.6.1.0之简单三层 首先介绍Solution的架构,一共分四个项目: Web :前台应用; BLL :业务处理层,如果嫌麻烦,可以再进一步抽象出来,然后将代码放置Web层的aspx.cs里面; Model :这个就不多说了,地球人都知道(数据实体类) SqlMaps:资源类,把配置文件和sql mapper文件全部打包起来。 二个文件夹: Include :iBatis.Net架构的dll文件 Log :放置log文件的文件夹,在web.config里配置 1.在一些特定的环境下,一站式的解决方案未必有效 系统的部分或全部数据来自现有数据库,处于安全考虑,只对开发团队提供几条Select SQL(或存储过程)以获取所需数据,具体的表结构不予公开。 开发规范中要求,所有牵涉到业务逻辑部分的数据库操作,必须在数据库层由存储过程实现。(银行大多有这样的限制) 系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。 2.iBATIS之于小型、简单系统:非常适用 iBATIS自己就很小并且简单 iBATIS不会对现存应用的设计或者数据库结构强加任何影响 iBATIS非常适合于有成长趋势的系统 3.iBATIS之于大型、企业级系统:为之而设计 iBATIS的某些特性使得它能够高效地处理大型数据集 iBATIS允许你用多种方式建立从对象到数据库的映射关系 MySpace已应用 4.使用于任何类型的关系数据库: 应用数据库 企业数据库 私有数据库 遗留数据库 简单性 性能 明确分工 可移植性:Java、.Net或者其他 开源 5.何时不该使用iBATIS 当你能永远拥有完全控制权 当你的应用需要完全动态的SQL 当你并没有使用关系数据库时 当iBATIS不起作用时
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值