Mybatis协会作为一对一而非一对多

时间:2017-02-06 22:02:54

标签: mybatis

为了清晰而编辑02/07/17

我在工作中使用Mybatis 3.3,但我遇到了障碍。我很确定我的resultMapper存在问题,但我在查找相关教程/信息方面遇到了一些困难。

我有一个现有的Java模型,Mybatis映射器和表;而且我正在尝试编写一个尽可能多地重用的新模块。我现有的模型如下所示:

class Document {
  Header header;
  List<Detail> details;
}

我希望将模型与不同的Mybatis映射器一起使用,以在Details和Headers之间产生1-1关系(即details.size()始终为1)。

我目前只能获得1份文件。它拉出表中的第一个标题,并将每个文档的每个细节附加到它。这是我的结果地图和我正在处理的查询。查询返回正确的结果,但Mybatis错误地包装它们。

<resultMap id="header" type="Header">
    <result property="id" column="ID" />
    <result property="title" column="TITLE" />
</resultMap>

<resultMap id="detail" type="Detail">
    <result property="id" column="ID" />
    <result property="title" column="INFO" />
</resultMap>

<resultMap id="document" type="Document">
  <association property="header" resultMap="header" />
  <association property="details" resultMap="detail" />
</resultMap>

SELECT 
  HEADER.ID,
  DETAIL.ID
FROM HEADER
JOIN DETAIL ON HEADER.ID = DETAIL.HEADER_ID

2 个答案:

答案 0 :(得分:0)

resultMap 文档中,使用集合代替 association 获取属性详细信息。

编辑02-08-17:

根据您的编辑,使事情更清晰:轻微的模型更改将更符合您的需求:

class Document {
  Header header;
  Detail detail;
}

但是你想保留1个元素的List<Detail>

我想到了这一点。它只需要添加“虚拟属性”=&gt; getter和setter来包装列表。

public void setSingleDetail(Detail detail) {
    this.details = Arrays.asList(detail);
}

public Detail getSingleDetail() {
    return null == this.details ? null : this.details.iterator().next();
}

但这还不够,因为它只是覆盖了详细信息列表。

如果查看方法org.apache.ibatis.executor.resultset.DefaultResultSetHandler#handleRowValuesForNestedResultMap。你会发现Mybatis不允许你想要的东西,它总是“分组”容器实体(如果你没有指定id属性,它将使用hash)。这也是需要getter的原因:与新行的值进行比较。

你想要做的是需要一个与Header关联的resultMap Detail(当然还有一个匹配结构的类),然后你得到一个结果/ Detail。

答案 1 :(得分:0)

要将行集映射到对象树,关键的是对象的标识。考虑这个例子:

header_id | detail_id
---------------------
        1 |        1
        1 |        2

有两种方法可以将此解析为对象树,Document作为根实体。第一种方法是使一个实体具有标题和两个Detail的集合。另一种方法是让两个Document每个都有一个Detail。这里的区别在于Document对象的身份。您需要告诉mybatis哪个列是Document实体的标识符。

出于您的目的,这应该是Detail

的ID

您需要更改查询和映射才能实现此目的。 主要目的是在此映射中将详细信息id指定为文档ID:

<resultMap id="document" type="Document">
  <id column="detail_id"/>
  <association property="header" resultMap="header" />
  <association property="details" resultMap="detail"/>
</resultMap> modify the query

您需要更改查询,以便详细信息ID列具有唯一名称,例如

SELECT 
  HEADER.ID,
  DETAIL.ID DETAIL_ID
FROM HEADER
 JOIN DETAIL ON HEADER.ID = DETAIL.HEADER_ID

但这会破坏Detail关联中其他列的映射。 要为resultMap使用Detail,您需要为详细信息表中的所有列添加相同的前缀,并在映射中指定:

<resultMap id="document" type="Document">
  <id column="detail_id"/>
  <association property="header" resultMap="header" />
  <association property="details" resultMap="detail" prefix="DETAIL_"/>
</resultMap> modify the query

请注意,由于mybatis错误,前缀应为大写。