resultMap for complex query - mybatis

I've got some query which returns data that does not have any object for it.
SELECT b.id,
b.publisher_id,
b.name,
b.size,
b.present,
CASE WHEN b.id in (SELECT book_id FROM downloads)
THEN true
ELSE false
END as downloading,
b.display,
b.download_date
FROM books as b
WHERE b.publisher_id = ${pId} AND b.display = true
LIMIT ${pageSize} OFFSET ${startId}
Field downloading does not have any column in database.
The mapper for object b is
<resultMap id="bookMap" type="Book">
<id column="id" property="id" />
<result column="publisher_id" property="publisherId" />
<result column="name" property="name" />
<result column="size" property="size" />
<result column="present" property="present" />
<result column="display" property="display" />
<result column="download_date" property="downloadDate" />
</resultMap>
How to create mapper for such object - where part is already existed resultMap but added new column.

One of the way is to create new class which will contain book with downloading status:
class BookWithDownloadingStatus {
private Book book;
private boolean downloading;
// I've omitted setters and getters
}
After that you can use this class to map result of the above query:
<resultMap id="bookWithDownloadingStatusMap" type="BookWithDownloadingStatus">
<result column="downloading" property="downloading"/>
<association property="book" resultMap="bookMap"/>
</resultMap>
<select id="getBookWithDownloadingStatus" resultMap="bookWithDownloadingStatusMap">
-- the above select
</select>
By the way, your query will not perform paging correctly. Database doesn't guarantee any order and without order limits and offsets are mostly useless. You should always specify ordering otherwise items may be distributed randomly between pages.

Related

Postgresql result does not match the database using mybatis

config.xml
<mapper namespace="com.###.mapper.EmployeeMapper" >
<resultMap id="EmployeeMap" type="com.###.model.Employee">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="type" property="type"/>
<result column="authority" property="authority"/>
<result column="tel" property="tel"/>
<result column="extra" property="extra"/>
</resultMap>
<select id="getById" parameterType="java.lang.String" resultMap="EmployeeMap" >
SELECT * from employee WHERE id=#{id}
</select>
</mapper>
test code
#Test
void insert() {
// 插入新行
Employee employee = new Employee("", "张三", "教授", null, "13122107768", null);
employeeMapper.insert(employee);
// 查询新行
Assert.assertEquals(employee,employeeMapper.getById(employee.getId()));
}
result
Expected: Employee(id=28, name=张三, type=教授, authority=null, tel=13122107768, extra=null)
Actual: Employee(id=28, name=张三, type=教授, authority=13122107768, tel=13122107768, extra=张三)
I got it! The entity class must have a no-argument constructor

Differents Tables in multiples objects blocs in MyBatis

I don't know how can i get the result of different tables in one object, I want fill this objets with only a query...
class HomeDto
{
String street;
Room room1;
Bath bath1;
}
//TABLE -> SIAS_TB_ROOM
class Room {
String idHome;
String floorRoom;
String doorRoom;
}
//TABLE -> SIAS_TB_BATH
class Bath {
String idHome;
String floorBath;
String doorBath;
}
<select id="findHome"
resultType="es.home.integration.model.HomeDto">
SELECT room1.floorRoom, bath1.doorBath
FROM SIAS_TB_BATH bath, SIAS_TB_ROOM room
WHERE bath.idHome = room.idHome
AND bath.floorBath='Purple'
</select>
Use result map for that like this:
<resultMap id="homeMap" type="es.home.integration.model.HomeDto">
<id property="id" column="idHome"> <!-- you need to add id to home -->
<association property="room1" javaType="es.home.integration.model.Room">
<result property="floorRoom" column="floorRoom"/>
<result property="doorRoom" column="doorRoom"/>
</association>
<association property="bath1" javaType="es.home.integration.model.Bath">
<result property="floorBath" column="floorBath"/>
<result property="doorBath" column="doorBath"/>
</association>
</resultMap>
Then use it in query:
<select id="findHome" resultMap="homeMap">
SELECT room.*, bath.foorBath, bath.doorBath
FROM SIAS_TB_BATH bath, SIAS_TB_ROOM room
WHERE bath.idHome = room.idHome
AND bath.floorBath='Purple'
</select>
You can simplify mapping further (for columns that are named the same as properties) by using autoMapping for associations like this:
<resultMap id="homeMap" type="es.home.integration.model.HomeDto">
<id property="id" column="idHome"> <!-- you need to add id to home -->
<association property="room1" javaType="es.home.integration.model.Room" autoMapping=true/>
<association property="bath1" javaType="es.home.integration.model.Bath" autoMapping=true>
<result property="aName" column="otherName"/>
</association>
</resultMap>

Reusing same ResultMap for two different queries in single fetch in mybatis

Requirement: I need to fetch partial data from two queries and populate the data into single resultmap.
Problem: When we get data from one query it is able to load the data into resultmap, but when I load the data from second query into the same result map the data is getting refreshed.
I guess it is creating a new map when we use same resultmap.Is there a way to make a resultmap available through out the session in mapper.xml.
Code
public Details {
private Term term;
}
public Term {
private String name;
private String location;
}
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.project.example.MyMapper">
<select id="select_form" parameterType="long" resultMap="select-result">
select id,name from details where id= #{id}
</select>
<select id="select_form_ext" parameterType="long" resultMap="select-result-ext">
select id,location from term where id= #{id}
</select>
<resultMap id="select-result" type="DetailsDto">
<association property="TermDto" column="ID" select="select_form_ext" />
<association property="TermDto" column="ID" resultMap="select-main-result" />
</resultMap>
<resultMap id="select-result-ext" type="TermDto">
<result property="location" column="LOCATION" />
</resultMap>
<resultMap id="select-main-result" type="TermDto" >
<result property="name" column="NAME" />
</resultMap>
</mapper>
Please give a try using the below steps.
Step1#: Remove the below line <association property="TermDto" column="ID" resultMap="select-main-result" /> from <resultMap id="select-result" >...
Step2#: Modify the ResultMapselect-result-ext as below
<resultMap id="select-result-ext" type="TermDto">
<result property="location" column="LOCATION" />
<result property="name" column="NAME" />
</resultMap>
Step3#: Execute/Run the application and check the Results.
Eg#:
<resultMap id="blogResult" type="Blog">
<association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectAuthor" resultType="Author">
SELECT * FROM AUTHOR WHERE ID = #{id}
</select>

How do I get to display the data i've retrieved from MyBatis in a collections property?

This is my mapper:
<mapper namespace="mybatis.mappers.ParentMapper">
<resultMap id="Parent" type="parentBean">
<result column="PARENT_ID" property="parentID" />
<result column="PARENT_NAME" property="parentName" />
<collection column="CHILD_NAME" property="children" ofType="String" javaType="ArrayList"/>
</resultMap>
<select id="retrieveParentsFromDB" resultMap="Parent">
SELECT PARENT_ID, P.PARENT_NAME, CHILD_NAME, C.idchildren
FROM MYBATIS.PARENTS P, MYBATIS.CHILDREN C
WHERE P.PARENT_NAME = 'PARENT A'
ORDER BY P.PARENT_ID, C.CHILD_NAME;
</select>
</mapper>
The CHILD_NAME COLUMN field denotes the children's names. But when I print out the values in a java file. What is retrieved seems to be the parent ID values. How do I fix this?
Turns out adding a column property in the collections property tag means you would use it in a nested query. I used this instead
<collection property="children" ofType="String" javaType="ArrayList">
<result column="CHILD_NAME" />
</collection>

Nested hashmap as result in mybatis

I have a requirement im Mybatis 3, to convert the result of a select query in which contains joins to nested hashmap result.
For example, consider the following mybatis mapper entry:
<select
id="testCaseSelect"
fetchSize="1000"
flushCache="false"
resultMap="testCaseResultMap" resultType="list">
SELECT TESTCASE_ID,
TC.TITLE,
TC.DESCRIPTION ,
TC.CREATION_DATE ,
TCS.STATUS_NAME,
TCP.PRIORITY_NAME ,
TCCBY.FIRST_NAME,
TCCBY.LAST_NAME,
TCST.SEQUENCE_NO ,
TCST.DESCRIPTION ,
TCST.EXPECTED_RESULT ,
TCCMNTS.COMMENT_TEXT ,
TCCMNTS.LOGGING_DATE
FROM TESTCASE TC
INNER JOIN TESTCASE_STATUS TCS
ON TC.STATUS_ID=TCS.STATUS_ID
INNER JOIN TESTCASE_PRIORITY TCP
ON TC.PRIORITY_ID=TCP.PRIORITY_ID
INNER JOIN USERS TCCBY
ON TC.CREATED_BY=TCCBY.USER_ID
LEFT JOIN TESTCASE_STEPS TCST
ON TC.TESTCASE_ID=TCST.TESTCASE_ID
LEFT JOIN TESTCASE_COMMENTS TCCMNTS
ON TC.TESTCASE_ID=TCCMNTS.TESTCASE_ID WHERE TESTCASE_ID BETWEEN 326780 AND 326800
</select>
<resultMap
id="testCaseResultMap"
autoMapping="true"
type="hashMap" >
<result
column="TESTCASE_ID"
property="tcId" />
<result
column="TITLE"
property="title" />
<result
column="DESCRIPTION"
property="description" />
<result
column="CREATION_DATE"
property="createdOn" />
<association
columnPrefix="TCS"
javaType="hashMap"
property="testCaseStatus" >
<id
column="STATUS_ID"
property="id" />
<result
column="STATUS_NAME"
property="status" />
</association>
<association
columnPrefix="TCP"
javaType="hashMap"
property="testCasePriority" >
<id
column="PRIORITY_ID"
property="id" />
<result
column="PRIORITY_NAME"
property="priority" />
</association>
<association
columnPrefix="TCCBY"
javaType="hashMap"
property="testCaseCreator" >
<id
column="USER_ID"
property="id" />
<result
column="FIRST_NAME"
property="firstName" />
<result
column="LAST_NAME"
property="lastName" />
</association>
<collection
columnPrefix="TCST"
javaType="hashMap"
ofType="list"
property="testCaseSteps" >
<id
column="STEP_ID"
property="id" />
<result
column="SEQUENCE_NO"
property="stepNo" />
<result
column="description"
property="step" />
<result
column="expected_result"
property="result" />
</collection>
<collection
columnPrefix="TCCMNTS"
javaType="hashMap"
ofType="list"
property="testCaseComments" >
<id
column="COMMENT_ID"
property="id" />
<result
column="COMMENT_TEXT"
property="comment" />
<result
column="LOGGING_DATE"
property="commentedOn" />
</collection>
</resultMap>
A test case object has a priority object, created by object, status object, a collection of steps and a collection of comments.
public static void main(String[] args)
{
SqlSessionFactory factory = getSqlSessionFactory();
SqlSession session = factory.openSession();
List<Map> list = session.selectList("testCaseSelect");
System.out.print(Arrays.toString(list.toArray()));
}
When I run the above, I get a list of 34 hashmaps one for each row returned. Each hashmap contains column_name and its value as key value pairs.
What I wanted is to have a hash map with the following structure:
root(hashMap)=>{
tcid(String),
title(String),
description(String),
createdOn(String),
testCaseStatus(hashMap)=>{
status(String)
},
testCasePriority(hashMap)=>{
priority(String)
},
testCaseCreator(hashMap)=>{
firstName(String),
lastName(String)
},
testCaseSteps(list of hashMap):[{
stepno(String),
step(String),
result(String),
}],
testCaseComments(list of hashMap):[{
comment(String),
commentedOn(String)
}],
}
Is it possible to achieve in mybatis?