好文档 - 专业文书写作范文服务资料分享网站

IBatis教程 

天下 分享 时间: 加入收藏 我要投稿 点赞

typeHandler属性声明了使用哪个类所实现的ITypeHandlerCallback接口来实现不同类实例的区分。这个接口提供了一个GetResult方法用于实现用户自定义区分逻辑。用户在这个接口中需要实现的是——通过读取记录的指定列值,进行逻辑判断,最后返回一个可用于同中的value属性值进行比较的数据值。

7.4.7简化结果映射(ImplicitResultMaps)

如果SQL指令返回的各列与所需的对象属性完全匹配,就不必显式声明结果映射(resultMap)。如果掌握了这个架构原理,我们就可以通过为SQL指令返回结果的列进行别名设置达到结果列与所需的结果对象属性名称完全一致,从而省略掉对resultMap的设计。下面的例子中,列名和属性名是完全匹配的,因此就可以省略掉它的resultMap。

例1.

例2.

需要指出的是,在有列的数据类型设置、空值设置或者其它对象属性值需要设置的情况下,不能这么简化。

另外,对于简化情况下的resultMap,字符大写也是个敏感的问题。比如,在一个对象中有一个“FirstName”属性和一个“Firstname”属性,当iBATIS对数据结果列和对象属性列进行名称匹配时,就会体现出对大小写的敏感性。我们不能保证哪个属性会被匹配成功。当然,几乎没有开发人员会把两个这样的命名属性置于一个对象中)

最后一点,当iBATIS对列和属性名进行自动映射时,会引起一些性能问题。如果第三方.NET数据库提供者对ResultSetMetaData支持不好的情况下就会有所体现。

7.4.8基本数据类型的结果PrimitiveResults(i.e.String,Integer,Boolean)

许多情况下,我们不需要返回一个具有多个属性的复杂对象结果,我们只需要得到一个String、Integer、Boolean等这样类型的值,那么

我们就不需要封装成对象,iBATIS就能为将这种基本数据类型转换成对象。如果我们需要基本数据类型的值,可以使用标准数据类型作为返回类,如下所示:

下例展示了返回基本数据类型列表的设置方式:

7.4.9ResultMap映射

有些情况下,对于那些属性很多的对象,我们只需要用它的一个键/值构成一个数据表,而每一属性都与这个表关联。对此,ResultMaps可以传递一个IDictionary实例作为属性对象。使用IDictionary的语法与使用对象的语法是有一样的。如下表所示:

在这个例子中,iBATIS为结果集的每一行生成一个包含Product数据的HashTable实例。property值中的id,code等都是字典项的关键字,映射列的值就是各个关键字的值。如下所示:

在这两个例子中,字典项包含什么是有SQL指令决定的,如果SQL指令在所获取的列信息上有变化,则iBATIS会自动生成新的字典集合。

7.4.10复合属性(complexProperties)

在关系数据库中,一个可能会引用另一表中的数据。对于这种情况,应用程序的业务实体对象中也可以包含另一个对象或者对象列表。一个类型可以嵌套在另一个类型中,这种机制称为“complextypes”,即复合类型。我们可以让查询指令返回一个信息完整的复合类型数据对象而不是一个简单类型。

通常情况下,一个数据表A的列column_A如果对另一个数据表B的列column_B具有引用关联(参考关系,外间关系),通常情况下clumn—_B是B表的主键列。Column_B列中的一个值与A表中的行具有1:1或者1:N的关系。往往从A表中获取的列Column_A并不是我们真正所需要的数据,那么我们就可以用复合类型来解决这个问题。

从iBATIS框架的角度来看,不是加载一个复合属性的问题,而是加载每一个复合属性的问题。为了解决这个问题,我们可以在ResultMap中声明一个SQL指令来完成对复合属性的数据加载(获取)。下面的例子中,“category”属性的\元素是一个复合属性。

在这个例子中,iBATIS框架会用selectCategory所代表的SQL指令完成对\属性数据的获取。每个category值都被传递到

\指令中,并返回一个category属性。当这个过程执行完后,每个Product实例都会有正确的category对象实例集合(之所以称为集合,是由于列的参考关联关系决定的)。

7.4.11避免N+1选择(1:1)

对于上一个例子,无论什么时候加载一个Product对象,都会执行两个SQL指令:一个指令用来获取Product对象,另一个用来获取Category对象。对于一个单独的Product来说,只是很微不足道的事情。但是,对于加载10个Product对象来说,那么会执行11个SQL指令。对于100个Product来说,则会有101个SQL执行需要运行。也就是执行的SQL指令数目总是N+1。见下例:

缓解这个问题的方法就是建立“selectCategory”指令的缓存。我们可能有100个Product,但仅有5个Category。那么运行一个SQL查询或者存储过程,iBATIS就会返回从缓存中获取Category数据。仍然是运行了101个指令,但不会命中数据库。

另一个解决的方法就是用一个标准的join运算的SQL指令来从外键的父表中获取我们所需要的列数据。用一个带有join的查询就可以获取我们需要从数据库中得到的全部列。但对象属性有嵌套关系时,可以使用“.”连接的方式引用嵌套对象的属性,如“category.description”。

下例通过在SQL指令中使用连接实现了与上例中一致的功能:

LAZYLoading与连接运算的比较(1:1)

需要强调的一点是“join”连接运算并不总是SQL设计的首选。当我们需要解决的应用中很少访问外键(或者引用)对象如Product类的category属性),避免join连接运算,也避免加载全部的category属性会使SQL执行运行效率更快。对于有外联接或者空值或者非索引列的数据库设计来说效果更明显。在这两种解决方法中,(启用缓存+子查询)的方法效果更好。通常来说,如果我们倾向于获取关联属性的时候,选用连接运算方法,否则,就用缓存+子查询的方法来解决。

如果我们对于使用哪种方法犹豫不定,请放松一下。无论使用哪种方法,都可以通过不改变源代码的方式进行方法更换。上面的两个例子就是很好的证明。强调的一点是如果能启动缓存,那么使用子查询的方法可以从缓存中获取查询结果。使用缓存绝大部分情况下不会引起问题。

7.4.12复合集合属性(ComplexCollectionProperties)

也可能需要加载的属性是一个复合对象列表。在数据库中,这样的数据关系表现为M:M关系,或者1:M关系。为了加载这个对象的IList,对于上面的实例来说,不需要进行修改。唯一不同的是在业务对象中这个属性必须是IList类型的变量,即必须是System.Collections.IList类型的

变量。例如,如果Category对象有一个IList类型的属性存放Product实例,则映射定义如下所示(假设Category有一个System.Collections.IList类型的属性“ProductList”):

7.4.13避免N+1选择列表集(1:M)

这同1:1的方法类似,但这个问题会涉及到更多潜在数据量。N+1的原因与7.4.11相同。

iBATIS完全解决了这个问题:

在程序中我们调用下面的语句:

IListmyList=sqlMap.QueryForList(\1002);

执行过程中,会先执行主查询,并把查询结果包含在Category类型的集合IList型变量myList中。List中的每个对象有一个ProductList属性,它的值也是从同一个查询结果数据中生成的列表,但是它由\定义的映射完成的数据捕获。这样我们就用一个数据库查询实现了列表嵌套的映射机制。

这个方法的重要组成是groupBy=\属性和:

需要指出的一点是对ProductList属性的结果映射定义中需要有它的显式命名空间——resultMapping=\,如果简化成\就会引起错误。使用这种方式我们可以解决任何深度的任何N+1问题。

LazyLoadingvs.Joins(1:MandM:N)Aswiththe1:1situationdescribedpreviously,it'simportanttonotethatusingajoinisnotalwaysbetter.Thisisevenmoretrueforcollectionpropertiesthanitwasforindividualvaluepropertiesduetothegreateramountofdata.Ifyouareinasituationwhereitisraretoaccesstherelatedobject(e.g.theProductListpropertyoftheCategoryclass)thenitmightactuallybefastertoavoidthejoinandtheunnecessaryloadingofthelistofproducts.Thisisespeciallytruefordatabasedesignsthatinvolveouterjoinsornullableand/ornon-indexedcolumns.Inthesesituationsitmightbebettertousethesub-selectsolutionwiththelazyloading.Thegeneralruleofthumbis:usethejoinifyou'remorelikelygoingtoaccesstheassociatedpropertiesthannot.Otherwise,onlyuseitiflazyloadingisnotanoption.

Asmentionedearlier,ifyou'rehavingtroubledecidingwhichwaytogo,don'tworry.Nomatterwhichwayyougo,youcanalwayschangeitwithoutimpactingyour.NETcode.Thetwoexamplesabovewouldresultinexactlythesameobjectgraphandareloadedusingtheexactsamemethodcall.Theonlyconsiderationisthatifyouweretoenablecaching,thentheusingtheseparateselect(notthejoin)solutioncouldresultinacachedinstancebeingreturned.Butmoreoftenthannot,thatwon'tcauseaproblem(yourapplicationshouldnotbedependentoninstancelevelequalityi.e.\

7.4.14复合主键/多个复合参数属性

我们可能已经注意到,上面的例子中,resultMap元素仅把列属性中的一个键作为对象的区分属性。这就表示只需要一个列就能把相关的映射指令联系起来。然而,有一种不同的语法用于向映射指令传递多个列作为参数。如果存在复合主键或者我们需要用多个列名作为一个参数,而不是用“#value#”格式,这种解决方法就是方便可用的。其语法结构是:

{param1=column1,param2=column2,…,paramN=columnN}

下面的例子中,PAYMENT表主键是由CustomerID和OrderID组合而成的:

一般来说,这是一种对可读性和可维护性的简单优化。

注意的是,本版本的iBATISDataMapper框架不会自动处理循环关联。当关系中存在引用关系(外键关系)树的的时候需要谨慎对待。

7.5ParameterMaps和ResultMaps所支持的数据类型:

CLRTypeObject/MapPropertyMappingResultClass/ParameterClass**TypeAlias**

IBatis教程 

typeHandler属性声明了使用哪个类所实现的ITypeHandlerCallback接口来实现不同类实例的区分。这个接口提供了一个GetResult方法用于实现用户自定义区分逻辑。用户在这个接口中需要实现的是——通过读取记录的指定列值,进行逻辑判断,最后返回一个可用于同中的value属性值进行比较的数据值。7.4.7简化结果映射(ImplicitResul
推荐度:
点击下载文档文档为doc格式
1ob9s1oo6h6et871e27e
领取福利

微信扫码领取福利

微信扫码分享