Reputation: 351
I stucked up with MyBatis select query. So, here are some details.
I have several java-classes (including constructors, getters, setters, etc):
class AttachmentHierarchy{
int id;
String title;
Attachment originalAttach;
}
class Attachment{
int id;
String author;
}
Also, I have such MyBatis query
@Select("SELECT
a.id id,
a.title title,
hierarchy.id hierarchy_id,
hierarchy.author hierarchy_author
FROM attachments a
JOIN attachments hierarchy on hierarchy.id = a.parent_id
WHERE a.id = #{attach_id}")
AttachmentHierarchy findAttachmentHierarchy(@Param(attach_id) int attachId);
Yes, I know, that current code looks strange and ugly, but I tried to simplify example. The main idea is that I want to Select complex object in one query using MyBatis annotations.
First, we can use @One annotation:
@Select("SELECT ...")
@Results(value = {
@Result(property = "originalAttach",
column = "parent_id",
one = @One(select = "findOriginalAttach"))
})
AttachmentHierarchy findAttachmentHierarchy(...);
@Select("SELECT a.id id,
a.author author
FROM attachment a
WHERE a.parent_id = #{parent_id}")
Attachment findOriginalAttach(@Param("parent_id") int parentId)
This solution looks good, but I don't want to invoke several queries to DB (in real life I want to fetch list of entries from several joined tables in one request).
Second, I know, that if Attachment
class contains only one field, say author
, I could do smth like:
@Results(value = {
@Result(property = "originalAttach",
column = "hierarchy_author",
typeHandler = AttachmentTypeHandler.class)
})
class AttachmentTypeHandler implements TypeHandler<Attachment>{
...
@Override
public Attachment getResult(final ResultSet rs, final String columnName) {
Attachment a = new Attachment();
a.setAuthor(rs.getString(columnName));
return a;
}
...
}
Finally, I know that @Result
annotation supports such syntax:
@Result(property = "originalAttach",
column = "{id=hierarchy_id, author=hierarchy_author}",
typeHandler = AttachmentTypeHandler.class)
But I have no idea how it could be used. It should somehow work with nested queries, creating "composites" object in mapping and passing null as column name to TypeHandler...
So, long story short, what's the best approach for fetching complex objects by single Select query using MyBatis and annotations? How should I use TypeHandler
and @Result
?
Upvotes: 3
Views: 3517
Reputation: 351
Ok, I found working solution based on @ConstructorArgs.
So, for my example I have to add constructor:
public AttachmentHierarchy(int id, String title, int originalId, String originalAuthor){
this.id = id;
this.title = title;
this.originalAttach = new Attachment(originalId, originalAuthor);
}
And for Mapper:
@Select("SELECT
a.id id,
a.title title,
hierarchy.id hierarchy_id,
hierarchy.author hierarchy_author
FROM attachments a
JOIN attachments hierarchy on hierarchy.id = a.parent_id
WHERE a.id = #{attach_id}")
@ConstructorArgs(value = {
@Arg(column = "id", javaType = int.class),
@Arg(column = "title", javaType = String.class),
@Arg(column = "hierarchy_id", javaType = int.class),
@Arg(column = "hierarchy_author", javaType = String.class)
})
AttachmentHierarchy findAttachmentHierarchy(@Param(attach_id) int attachId);
Please note, that you have to specify exact javaTypes in constructorArg.
This works for me, but I'm still looking for more simple and nice solution.
Upvotes: 3