1. 程式人生 > >MyBatis實戰——resultMap,resultType簡介,關聯物件

MyBatis實戰——resultMap,resultType簡介,關聯物件

一、概述
MyBatis中在查詢進行select對映的時候,返回型別可以用resultType,也可以用resultMap,resultType是直接表示返回型別的,而resultMap則是對外部ResultMap的引用,但是resultType跟resultMap不能同時存在。
在MyBatis進行查詢對映時,其實查詢出來的每一個屬性都是放在一個對應的Map裡面的,其中鍵是屬性名,值則是其對應的值。
①當提供的返回型別屬性是resultType時,MyBatis會將Map裡面的鍵值對取出賦給resultType所指定的物件對應的屬性。所以其實MyBatis的每一個查詢對映的返回型別都是ResultMap,只是當提供的返回型別屬性是resultType的時候,MyBatis對自動的給把對應的值賦給resultType所指定物件的屬性。

②當提供的返回型別是resultMap時,因為Map不能很好表示領域模型,就需要自己再進一步的把它轉化為對應的物件,這常常在複雜查詢中很有作用。

二、ResultType

public class Blog {  
       private int id;  
       private String title;  
       private String content;  
       private String owner;  
       private List<Comment> comments;  
}  
其所對應的資料庫表中儲存有id、title、Content、Owner屬性。

<typeAlias alias="Blog" type="com.tiantian.mybatis.model.Blog"/>  
<select id="selectBlog" parameterType="int" resultType="Blog">  
      select * from t_blog where id = #{id}  
</select>  
MyBatis會自動建立一個ResultMap物件,然後基於查找出來的屬性名進行鍵值對封裝,然後再看到返回型別是Blog物件,再從ResultMap中取出與Blog物件對應的鍵值對進行賦值。



三、resultMap
當返回型別直接是一個resultMap的時候也是非常有用的,這主要用在進行復雜聯合查詢上,因為進行簡單查詢是沒有什麼必要的。先看看一個返回型別為resultMap的簡單查詢,再看看複雜查詢的用法。

①簡單查詢的寫法
<resultMap type="Blog" id="BlogResult">  
        <id column="id" property="id" />  
        <result column="title" property="title" />  
        <result column="content" property="content" />  
        <result column="owner" property="owner" />  
    </resultMap>  
    <select id="selectBlog" parameterType="int" resultMap="BlogResult">  
        select *  
        from t_blog where id = #{id}  
    </select>  
select對映中resultMap的值是一個外部resultMap的id,表示返回結果對映到哪一個resultMap上,外部resultMap的type屬性表示該resultMap的結果是一個什麼樣的型別,這裡是Blog型別,那麼MyBatis就會把它當作一個Blog物件取出。resultMap節點的子節點id是用於標識該物件的id的,而result子節點則是用於標識一些簡單屬性的,其中的Column屬性表示從資料庫中查詢的屬性,Property則表示查詢出來的屬性對應的值賦給實體物件的哪個屬性。簡單查詢的resultMap的寫法就是這樣的。

②複雜查詢
有一個Comment類,其中有一個Blog的引用,表示是對哪個Blog的Comment,那麼在查詢Comment的時候把其對應的Blog也要查出來賦給其blog屬性。
public class Comment {  
  
    private int id;  
      
    private String content;  
      
    private Date commentDate = new Date();  
      
    private Blog blog;  
}

其寫法是這樣的

<!--來自CommentMapper.xml檔案    -->  
    <resultMap type="Comment" id="CommentResult">  
        <association property="blog" select="selectBlog" column="blog" javaType="Blog"/>  
    </resultMap>  
      
    <select id="selectComment" parameterType="int" resultMap="CommentResult">  
        select * from t_Comment where id = #{id}  
    </select>  
      
    <select id="selectBlog" parameterType="int" resultType="Blog">  
        select * from t_Blog where id = #{id}  
    </select>  


其訪問情況是這樣的,先是請求id為selectComment的select對映,然後得到一個id為CommentResult的ResultMap物件,我們可以看到在對應的resultMap的返回型別是一個Comment物件,其中只有一個association節點,而沒有像前面說的簡單查詢所對應的id,result子節點,但是其仍會把對應的id等屬性賦給Comment物件,這就是前面所說的MyBatis擁有自動封裝功能,只要你提供了返回型別,MyBatis會根據自己的判斷來利用查詢結果封裝對應的物件(所以前面的簡單查詢中,如果你不在resultMap中明確的指出id對應哪個欄位,title對應哪個欄位,MyBatis也會根據自身的判斷來幫你封裝,MyBatis的自身判斷是把查詢的field或其對應的別名與返回物件的屬性進行比較,如果相匹配且型別也相匹配,MyBatis則會對其進行賦值。)

在上面對應的resultMap中關聯了一個blog屬性,其對應的JAVA型別為Blog,在上述的寫法中,關聯物件是通過子查詢來進行關聯的,當然也可以直接通過關聯查詢來進行關聯。上面的association子節點中,Property屬性表示是resultMap返回型別的哪個關聯屬性,對於上面的例子就是Comment管理的blog屬性;select表示進行哪個select對映來對映對應的關聯屬性,即會去請求id為select所對應的值的select對映 來查詢出其所關聯的屬性物件;Column表示當前關聯物件在id為CommentResult的resultMap中所對應的鍵值對,該鍵值對將作為對關聯物件子查詢的引數,即把在selectComment中查詢出來的blog屬性的值作為引數傳給進行關聯物件blog的子查詢selectBlog的引數;javaType表示當前關聯物件在JAVA中是什麼型別。

上述介紹的是一對一或一對多的情況下,對一的一方的關聯的查詢。在實際應用中還有一個用的比較多的應用是通過一的一方查出對應的多的一方,在拿出多的一方的時候也同樣要把一的一方關聯上,即在上述例子中,在拿出Blog物件的時候,就把其對應的Comment全部拿出來,在拿出Comment的時候也還是需要把其對應的Blog拿出來,這是在JAVA中通過一次請求就拿出來的。寫法如下:


<!-- 來自BlogMapper.xml檔案 -->
	<resultMap type="Blog" id="BlogResult">
		<id column="id" property="id"/>
		<collection property="comments" select="selectCommentsByBlog" column="id" ofType="Comment"></collection>
	</resultMap>

	<resultMap type="Comment" id="CommentResult">
		<association property="blog" javaType="Blog" column="blog" select="selectBlog"/>
	</resultMap>

	<select id="selectBlog" parameterType="int" resultMap="BlogResult">
		select * from t_blog where id = #{id}
  	</select>

<!--  通過Blog來查詢Comment	-->
  	<select id="selectCommentsByBlog" parameterType="int" resultMap="CommentResult">
  		select * from t_Comment where blog = #{blogId}
  	</select>



上述請求的入口是id為selectBlog的select對映,返回結果為id為BlogResult的resultMap,id為BlogResult的型別為Blog,其中指定了id的屬性和欄位,指定id將對MyBatis內部的構造作用非常大。其中關聯了一個comments物件,因為一個Blog可以有很多Comment,該comments為一個集合,所以用集合collection進行對映,其中的select還是表示進行哪個子查詢來查詢對應的comments,column表示把上述查出來的哪個欄位值當作引數傳給子查詢,ofType也是表示返回型別,這裡的返回型別是集合內部的型別,之所以用ofType而不是用type是MyBatis內部為了和關聯association進行區別。 

測試程式碼:


	@Test
	public void selectCommentsByBlogTest() {
		SqlSession session = Util.getSqlSessionFactory().openSession();
		CommentMapper commentMapper = session.getMapper(CommentMapper.class);
		List<Comment> comments = commentMapper.selectCommentsByBlog(6);
		for (Comment comment : comments)
			System.out.println(comment);
		session.close();
	}

	/**
	 * 查詢單條記錄
	 */
	@Test
	public void testSelectOne() {
		SqlSession session = Util.getSqlSessionFactory().openSession();
		BlogMapper blogMapper = session.getMapper(BlogMapper.class);
		Blog blog = blogMapper.selectBlog(6);
		List<Comment> comments = blog.getComments();
		if (comments != null) {
			System.out.println("--------------Comments Size------------" + comments.size());
			for (Comment comment : comments)
				System.out.println(comment);
		}
		session.close();
	}