为IDictionary,则property是相应key的名称。同一property值可以出现多次,这取决于它在语句中出现的次数。

column

用于定义存储过程的参数名称。

direction

可用于指定存储过程参数的方向。其值可以是Input,Output或InputOutput。

dbType

用于显式地指定参数对应的列类型。对于某些操作,一些ADO.NET provider不能判断列的类型,此时dbType必须指定。

此特性仅在列为nullable时是必需的。此外,在显式指定日期类型时也需要此特性。尽管.NET仅有一种日期值类型(System.DateTime),大多数数据库却不止一个。通常情况下,数据库至少有三种不同的日期类型(Date,DateTime,TimeStamp)。为使映射过程能够正确,我们可能需要指定列的dbType。

type

用于指定前面的property的CLR类型。在向存储过程传入InputOput和Output类型的参数时,该特性很有用。

正常情况下,property的类型可通过反射获得,但对于IDictionary类型的参数就无能为力了,此时类型被假定为Object。

nullValue

nullValue可以设置为任何的有效值(这取决于property的类型)。

注意:对于值类型(int,double,datetime等)的属性,它们是不能为null的,那如何向数据库中插入null值呢?可以采用nullValue,比如对于Age列(int类型),我们可以指定nullValue为0,这意味着如果该属性未设置(C#中,int属性的默认值为0),那么会向数据库插入NULL。在.NET2.0中也可以使用nullable类型,此时更为方便。请参考我的小文。

size

设置列的最大尺寸。

precision

设置数字值的精度。

scale

设置小数的位数。

typeHandler

用于自定义类型处理器(Custom Type Handler)。

内联参数在多数情况下效果不错。如果您希望改善性能,或者遇到了意外的情况,外部参数可能就用得上了。在第5章中,我们会更全面地讨论外部参数,在这里,暂不需要。

4.3.2 重温内联参数

如果您更喜欢使用内联参数,同样可以为参数指定更多的信息,如属性的类型,类的类型以及null值替换(即nullValue特性)。看下面四个例子:

<statement id="insertProduct" parameterClass="Product">
    insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)
    values (#id#, #description#)
</statement>

这是最简单的情况,下面这个例子指定了dbType:

<statement id="insertProduct" parameterClass="Product">
    insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)
    values (#id:int#, #description:VarChar#)
</statement>

下面这个例子指定了nullValue:

<statement id="insertProduct" parameterClass="Product">
    insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)
    values (#id:int:-999999#, #description:VarChar#)
</statement>

类似于Java中的DataMapper,内联参数还有另外一种语法,使用逗号。

<update id="UpdateAccountViaInlineParameters" parameterClass="Account">
    update Accounts set
    Account_FirstName = #FirstName#,
    Account_LastName = #LastName#,
    Account_Email = #EmailAddress,type=string,dbType=Varchar,nullValue=no_email@provided.com#
    where
    Account_ID = #Id#
</update>

4.3.3 标准类型的参数(standard type parameter

在实际开发中,我们会发现很多语句只接受单个参数,通常为int或string。此时并不需要将其封装在另一个对象中,直接使用标准库对象(string, int等)就可以了,下面是一个例子:

<statement id="getProduct" parameterClass="System.Int32">
    select * from PRODUCT where PRD_ID = #value#
</statement>

假定PRD_ID为数字类型,在调用该语句时,可以传入一个标准的int对象。#value#参数会替换为传入的int值。此处的value仅仅是一个占位符,您可以根据需要将其替换为其它名称。

为方便起见,iBATIS框架提供了基元类型的别名,比如,int可用于代替System.Int32。要了解这些别名的完整内容,请参考iBATIS.NET的官方文档。

4.3.4 IDictionary类型的参数

<statement id="getProduct" parameterClass="System.Collections.IDictionary">
    select * from PRODUCT
    where PRD_CAT_ID = #catId#
    and PRD_CODE = #code#
</statement>

我们也可以使用IDictionary类型的对象作为参数。通常可以使用Hashtable。看下面的例子:

看看这条语句,跟前面出现的没有什么不同。如果传入的对象是Hashtable类型,它必须要包含有名称为catId和code的键,而键所对应的值必须要适合于列的类型,这些要求与使用普通的对象是一样的。

为方便起见,iBATIS框架也提供了IDictionary类型的别名。因此,可以用map或hashtable来代替System.Collections.Hashtable。要了解这些别名的完整内容,请参考iBATIS.NET的官方文档。

OK,至此我们已经知道了如何输入参数了,下面就来看看如何获取输出值了。

4.4结果映射(result map

Result Map将从数据库查询所得的结果映射到对象的属性。在使用映射语句时,Result Map是我们要理解的最常用也是最重要的特性之一。

通过Result Map我们可以控制如何从查询结果中获取数据,以及列是如何映射到对象的属性的。Result Map可以描述列的类型、null值的替换以及复杂属性(包括集合)的映射。

4.4.1 扩展Result Map

可选的extends特性值可以设置为另一个Result Map的名称,这样就可以复用指定Result Map的映射方式了。“父级”Result Map的所有属性都将作为当前Result Map的一部分,“父级”Result Map的值在当前Result Map之前进行设置,其效果类似于类的继承。

提示:“父级”Result Map必须在“子级”Result Map之前定义。

4.4.2 <resultMap>的特性

<resultMap>接受三个特性:

特性

描述

id

必需的,为Result Map提供唯一标识。

class

可选的,指定当前Result Map使用的类。可以设置为类的完整名称或别名。

extends

可选的,指定要进行“继承”的Result Map。

4.4.3 <constructor>元素

<constructor>元素必须与result class的构造函数签名相匹配。如果指定了此元素,iBATIS用它来实例化结果对象(result object)。

4.4.4 <result>元素

<resultMap>元素包含一个或多个<result>子元素,用以将执行SQL的结果集映射至对象的属性。

特性

描述

property

必需的,表示结果对象的属性名称。

column

必需的,指定结果集中的列名称,使用该列来产生当前属性。

columnIndex

可选的,指定列的索引,该特性对性能会有轻微的帮助。99%的应用程序中是不需要的,而且它还会牺牲可维护性和可读性。另外一些provider中,该特性可能对性能没有任何帮助。

dbType

用于显式地指定列的类型。由于CLR和数据库中类型的不一致,该特性比较有用,尤其是对datetime和string类型。

type

用于显式地指定结果对象属性的CLR类型。通常属性的类型可通过反射获得,但在映射到Hashtable之类的对象时就无能为力了。

resultMapping

该特性的值可以设置为另一个Result Map的名称,借助后者来填充属性。如果使用的Result Map位于另一个文件中,则必须要使用它的完全限定名称(加上命名空间)。

nullValue

用于指定null值的替代值,该特性可以设置为任何有效的值(取决于属性的类型)。如果属性类型为值类型,则其值不可能为null,如果列的值为null,那么通过该特性可以将属性设定为某个常量值。另一方面,如果属性可以为null,我们可能想用某个常量值而不是null来表示它,这个时候nullValue特性也是有用的。

select

用于描述对象间的关系,并自动加载复杂类型(即用户定义类型)。其值必须为另一映射语句的名称。

lazyLoad

联合使用lazyLoad和select特性,可以指定select特性所指定语句的结果是否要延迟加载。延迟加载对IList和IList<>的支持是透明的,对强类型的集合类的支持则需要Castle.DynamicProxy组件。

typeHandler

允许使用自定义类型处理器(Custom Type Handler)。这样就可以扩展DataMapper的能力,来处理那些provider特定的类型或者是provider不支持的类型。

代码示例:nullValue的使用

<resultMap id="get-product-result" class="product">
    <result property="id" column="PRD_ID"/>
    <result property="description" column="PRD_DESCRIPTION"/>
    <result property="subCode" column="PRD_SUB_CODE" nullValue="-9999" />
</resultMap>

注意:如果PRD_SUB_CODE列的值为null,则subCode属性的值将设置为-9999。记住,在插入/更新数据时,Parameter Map的nullValue特性也要进行设置,这样才能一致。实际上有了nullable类型后,该特性可以不使用了。

4.4.5 隐式的结果映射

如果SQL语句返回的列与结果对象的属性相匹配,那么显式的Result Map就不再必要了。在下面的例子中,列的名称和属性的名称已然匹配,因此无需声明Result Map。

<statement id="selectProduct" resultClass="Product">
    select
    id,
    description
    from PRODUCT
    where id = #value#
</statement>

但是,如果列的名称和属性名称不一致,而列名不可能修改(比如使用其它公司开发的数据库),那该怎么办呢?可以使用列的别名,看下例:

<statement id="selectProduct" resultClass="Product">
    select
    PRD_ID as id,
    PRD_DESCRIPTION as description
    from PRODUCT
    where PRD_ID = #value#
</statement>

当然,此时就不能指定dbType、nullValue或者其它的特性了(不要太贪心…)。

区分大小写是隐式Result Map的另一个问题。诚然,我们可为一个类同时定义“FirstName”和“Firstname”两个属性,在iBATIS进行映射时,它就不能保证是匹配哪个属性了(当然了,没几个开发人员会定义这样相近的两个属性)。

最后,隐式Result Map会有性能损失,如果我们使用第三方的.NET数据库provider,而它又对ResultSetMetaData支持很差,那损失就更明显了。

4.4.6 返回基元类型的结果(如string,int等)

很多时候,并不需要返回一个具有多个属性的对象,我们需要的仅仅是单个的string,int,bool等类型的值。这时,您可以指定标准类型作为结果类型,如:

<select id="selectProductCount" resultClass="System.Int32">
    select count(*) from PRODUCT
</select>

结果类型也可使用iBATIS框架提供的别名,比如,int可用于代替System.Int32。要了解这些别名的完整内容,请参考iBATIS.NET的官方文档。

4.4.7 返回IDictionary类型的结果

有些时候我们需要的只是包含数据的键/值列表。Result Map可以生成一个IDictionary类型的实例,其语法与普通的POCO对象一样:

<resultMap id="select-product-result" class="hashtable">
    <result property="id" column="PRD_ID"/>
    <result property="code" column="PRD_CODE"/>
    <result property="description" column="PRD_DESCRIPTION"/>
    <result property="suggestedPrice" column="PRD_SUGGESTED_PRICE"/>
</resultMap>

在这个例子中,iBATIS会为每一行创建一个Hashtable实例,这个实例包含了返回的数据,属性名id、code等均作为Hashtable的key,列的值则作为Hashtable的值。

也可以使用IDictionary类型作为隐式的Result Map:

<statement id="selectProductCount" resultClass="hashtable">
    select * from PRODUCT
</statement>

Hashtable包含的值取决于列的值。如果列发生了变化(比如添加或删除了列),返回的结果也会随之发生变化。

注意:某些provider可能将返回的列名称定为大写或小写,此时要注意使用正确的key名称。

4.5 小结

在本章中,我们探讨了POCO,SQL Map的API,映射语句。随着您对这些内容的熟悉,创建映射语句也会越来越简单,就像其它任何事情一样,熟能生巧。

如果您希望尽可能地减少运行时的错误,就要显式声明!使用显式的参数和结果映射,并且要使用强类型的对象。这样,您的程序会启动更快(因为iBATIS会尝试推导所有内容),运行更快,使用的内存更少。

在下章中,我们将研究iBATIS支持的非查询语句,届时,我们就能够了解数据库维护所需的各种基本操作了。

点击这里下载示例代码(数据库为Northwind,请修改SqlMap.config中的配置)。

下一篇:iBATIS In Action:执行非查询语句(一);

本文转自一个程序员的自省博客园博客,原文链接:http://www.cnblogs.com/anderslly/archive/2007/11/04/ibatisusingmappedstatement02.html,如需转载请自行联系原作者。

iBATIS In Action:使用映射语句(二)相关推荐

  1. iBATIS In Action:使用映射语句(一)

    在前面的章节中,我们了解了iBATIS的sqlMap.config文件的配置,还给出了一个映射语句文件的示例.现在您应该具备了一定基础,可以进一步完善我们的数据访问层了. 本章和下一章(执行非查询语句 ...

  2. iBATIS In Action:执行非查询语句(二)

    本章内容包括 iBATIS API的更多内容 插入数据 更新和删除数据 使用存储过程 5.3 更新和删除数据 至此,我们已经学习了如何向数据库插入数据以及获取相应记录的键值,再来看看如何更新和删除数据 ...

  3. iBATIS In Action:什么是iBATIS(二)

    2.5 iBATIS快速上手 iBATIS框架非常简单,它上手起来同样简单.有多简单呢?使用iBATIS只要五分钟我们就可以创建一个完整的应用程序了--当然这不是大型的ERP(Enterprise R ...

  4. iBATIS In Action(六)执行非查询语句

    对数据库执行查询无疑很重要,但多数程序同时也需要将数据写入数据库.在本章中,我们将探究使用iBATIS操作数据库的几种方式.本章的内容以第4章介绍的概念为基础,因此,如果您刚开始接触iBATiS,还没 ...

  5. iBATIS In Action:使用高级查询技术(一)

    可以考虑根据对象的关系(关联)来定义数据模型,然后使用iBATIS将它们一起加载.例如,如果在数据库中,Account记录对应着相关的Order记录,而Order又对应着相关的OrderItem记录, ...

  6. Ibatis in action 电子书

    电子书 是ibatis 项目组写的ibatis开发的权威书籍.现在只有电子版,目前使用Java作为描述的平台,这个书对于.NET和Ruby一样适用. 如果你的程序必须直接运行SQL语句的话,那前面两个 ...

  7. ibatis Dynamic总结(ibatis使用安全的拼接语句,动态查询)

    ibatis中使用安全的拼接语句,动态查询,ibatis比JDBC的优势之一,安全高效  说明文字在注释中 一.引入 一个小例子   <select id="selectAllProd ...

  8. Mybatis基于XML配置SQL映射器(二)

    Mybatis之XML注解 之前已经讲到通过 mybatis-generator 生成mapper映射接口和相关的映射配置文件: 下面我们将详细的讲解具体内容 首先我们新建映射接口文档  sysUse ...

  9. CCNP精粹系列之十八--路由映射实战二,博主推荐文章

    路由映射实战二 本篇博文和上一篇是紧密结合的,只是在上个试验的基础上作了改动,达到其他的试验效果. 试验二: 在R1上增加一个网段,并发布路由.这里采用三种方法. 如下是第一种,是在试验一的基础上直接 ...

最新文章

  1. SVN建立分支和合并代码
  2. shell对文本进行操作命令
  3. 微服务中为什么需要服务发现?
  4. php做一个计算日期之间天数,PHP计算任意两个日期之间的天数
  5. 前端学习(1973)vue之电商管理系统电商系统之完成修改的操作
  6. Java B2B2C多用户电子商务平台SpringCloud/Boot
  7. Hadoop之高可用原理
  8. MySQL索引的Index method中btree和hash的优缺点
  9. ODOO12 自定义销售报价单样式
  10. win10终端中如何切换磁盘
  11. 广告中的CPM、CPC、CPA解释
  12. 汇率换算自然语言理解功能JAVA DEMO
  13. 六祎-Mybatis高速下载通道
  14. PyCharm设置中文(官方插件版)
  15. 树莓派4B连不上wifi的一个意想不到的原因
  16. HTTP中的301、302、303、307、308
  17. 【数论】博弈论 —— nim游戏
  18. uboot 修改启动logo
  19. 图像预处理 mean=[0.485, 0.456, 0.406] std=[0.229, 0.224, 0.225] 的由来以及使用
  20. 读书笔记|《金字塔原理》_第一章

热门文章

  1. win7硬盘安装过程图解
  2. 如何安装MiniGUI 3.0在Linux PC
  3. 奔跑吧linux内核_别了,Linux 的魔法时代!
  4. k歌的录音伴奏合成技术如何实现_2019年中国在线K歌行业市场现状,在线K歌用户女性占比较高...
  5. java protobuf 例子_java使用protobuf例子
  6. spss回归分析_回归分析中的简单斜率检验:用SPSS或jamovi实现
  7. 朴素贝叶斯算法和逻辑回归算法的区别?
  8. php mysql 大量读取_PHP使用PDO从mysql读取大量数据处理详解
  9. 基于redis分布式锁实现的多线程并发程序(原创)
  10. 字符串匹配的Boyer-Moore算法