Reusing same ResultMap for two different queries in single fetch in mybatis - 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>

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>

MyBatis - Fetch multiple collections

I am preety new to MyBatis so wanted to if somebody can help me with my issue.
The problem surrounds around Television programs.
Objects
Programs
Products
Mappings
One Program shows multiple products
Programs can be repeated multiple times in future or have been in past
Select Query
<select id="findsProgramGuideDetails" resultMap="programGuideDetails" parameterType="map">
select
sourceCode, showCode, productNumber, programTitle, OTHER_FIELDS
from MY_TABLE where SOME_CONDITIONS
</select>
Result map
<resultMap id="programGuideDetails" type="com.qvc.integration.batch.programguide.vo.UdbProgramGuideDataloadDetailsVo">
<id property="sourceCode" column="sourceCode"
typeHandler="com.test.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
<result property="showCode" column="showCode"
typeHandler="com.test.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
<result property="programTitle" column="programTitle"
typeHandler="com.test.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
... Other Result tags
Collection inside Resultmap
<collection property="plannedShows" ofType="com.test.programguide.dataload.model.vo.PlannedShow" column="programTitle">
<id property="showTitle" column="programTitle"
typeHandler="com.test.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
<result property="id" column="sourceCode"
typeHandler="com.test.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
<result property="channelCode" column="channel"
typeHandler="com.test.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
<result property="startDate" column="startDate"
typeHandler="com.test.integration.batch.programguide.typehandler.DateFormatTypeHandler" />
<result property="endDate" column="endDate"
typeHandler="com.test.integration.batch.programguide.typehandler.DateFormatTypeHandler" />
</collection>
<collection property="productDetails" ofType="com.qvc.programguide.dataload.model.vo.ProductDetail" column="sourceCode">
<id property="productId" column="productNumber"
typeHandler="com.qvc.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
<result property="productName" column="productName"
typeHandler="com.qvc.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
<result property="brandId" column="brandId"
typeHandler="com.qvc.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
<result property="brandName" column="brandName"
typeHandler="com.qvc.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
<result property="priceCode" column="priceCode"
typeHandler="com.qvc.integration.batch.programguide.typehandler.StringTrimmingTypeHandler" />
</collection>
Problem
Multiple products are coming properly with every record but the plannedShows i.e. previous and upcoming repeat telecast is fetching itself only.
Any help would be appreciated.
There relation one to many is simple, use the collection tag and define the parameters to join the keys, in this case i also used a request parameter as a subselect column.
<resultMap type="package.pojo.Recipient" id="receiversResultMap">
<result column="EMAIL_ADDRESS" property="emailAddress" />
<result column="END_TS" property="endTs" />
<result column="NAME" property="name" />
<result column="RECIPIENT_ID" property="recipientId" />
<result column="START_TS" property="startTs" />
<result column="TYPE" property="type" />
<result column="UPDATE_TS" property="updateTs" />
<result column="USER_ID" property="userId" />
<collection property="messages" column="{param1=RECIPIENT_ID, param2=LOCKID}" javaType="ArrayList" ofType="java.util.List" select="findMessages" />
</resultMap>
<select id="findReceivers" resultMap="receiversResultMap">
SELECT
EMAIL_ADDRESS,
END_TS,
NAME,
RECIPIENT_ID,
START_TS,
TYPE,
UPDATE_TS,
USER_ID,
#{lockId} AS LOCKID
FROM T_DOPA0_RECIPIENT
</select>
<resultMap type="package.pojo.Message" id="messageResultMap">
<result column="EMAIL_USED" property="emailUsed" />
<result column="LOCK_ID" property="lockId" />
<result column="MESSAGE_ID" property="messageId" />
<result column="RECEIPT_TS" property="receiptTs" />
<result column="RECIPIENT_ID" property="recipientId" />
<result column="SELECTED" property="selected" />
<result column="SEND_TS" property="sendTs" />
<result column="TYPE" property="type" />
<result column="DESCRIPTION" property="description" />
</resultMap>
<select id="findMessages" resultMap="messageResultMap">
SELECT
EMAIL_USED,
LOCK_ID,
MESSAGE_ID,
RECEIPT_TS,
RECIPIENT_ID,
SELECTED,
SEND_TS,
TYPE,
DECODE.DESCRIPTION
FROM T_MESSAGE MESSAGE
LEFT OUTER JOIN D_MESSAGE_TYPE DECODE ON DECODE.LOCK_MESSAGE_TYPE = MESSAGE.TYPE
WHERE RECIPIENT_ID = '${param1}'
AND LOCK_ID = '${param2}'
</select>

resultMap for complex query

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.

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?