Как выбрать результаты типа текстового массива в mybatis? - PullRequest
0 голосов
/ 01 мая 2019

Например, в PostgreSQL есть таблица с столбцом типа text[]:

CREATE TABLE t
(
    id integer,
    name text,
    tags text[],
    PRIMARY KEY (id)
)

Теперь я хочу выбрать tags двумя способами:

  1. Выберите tags, используя первичный ключ id, и результат должен иметь тип List<String>
  2. Выберите tags, используя name, а результат должен быть типа List<List<String>>

Как мне написать MyBatis mapper для достижения этой цели?

Ответы [ 2 ]

1 голос
/ 02 мая 2019

Вы все еще можете использовать Java mapper, однако MyBatis внутренне вызывает SqlSession#selectList, когда типом возврата является List, а это не то, что вам нужно.
Таким образом, вам нужно использовать Object в качестве возвращаемого типа.

@Select("select tags from t where id = #{id}")
Object getTagById(Integer id);

@Select("select tags from t where name = #{name}")
List<Object> getTagByName(String name);

И зарегистрируйте ваш обработчик типов глобально в конфиге. т.е. * +1008 *

<typeHandlers>
  <typeHandler handler="xxx.yyy.ListArrayTypeHandler" />
</typeHandlers>

или

configuration.getTypeHandlerRegistry()
  .register(ListArrayTypeHandler.class);

Для полноты вот пример реализации обработчика типа.

import java.sql.Array;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

@MappedJdbcTypes({ JdbcType.ARRAY })
@MappedTypes({ Object.class })
public class ListArrayTypeHandler extends BaseTypeHandler<List<?>> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i,
      List<?> parameter, JdbcType jdbcType) throws SQLException {
    //  JDBC type is required
    Array array = ps.getConnection().createArrayOf("TEXT", parameter.toArray());
    try {
      ps.setArray(i, array);
    } finally {
      array.free();
    }
  }

  @Override
  public List<?> getNullableResult(ResultSet rs, String columnName) throws SQLException {
    return extractArray(rs.getArray(columnName));
  }

  @Override
  public List<?> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    return extractArray(rs.getArray(columnIndex));
  }

  @Override
  public List<?> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    return extractArray(cs.getArray(columnIndex));
  }

  protected List<?> extractArray(Array array) throws SQLException {
    if (array == null) {
      return null;
    }
    Object javaArray = array.getArray();
    array.free();
    return new ArrayList<>(Arrays.asList((Object[])javaArray));
  }
}

К вашему сведению, чтобы сохранить List в столбце tags, вам может потребоваться явно указать обработчик типа.

insert into t (...) values (#{id}, #{name},
  #{tags,typeHandler=xxx.yyy.ListArrayTypeHandler})
0 голосов
/ 01 мая 2019

Вы не первый с этой проблемой.

Проект common-mybatis имеет обработчик типа именно для этого случая использования: StringArrayTypeHandler

Просто добавьте его в конфигурацию MyBatis:

    <typeHandlers>
        <typeHandler handler="org.gbif.mybatis.type.StringArrayTypeHandler"/>
    </typeHandlers>

... и затем для отображения это так же просто, как:

    <select id="getTagsById" resultType="java.util.List">
        SELECT tags FROM t WHERE id = #{id}
    </select>

    <select id="getTagsByName" resultType="java.util.List">
        SELECT tags FROM t WHERE name = #{name}
    </select>

... и вкод:

try (SqlSession session = sessionFactory.openSession()) {
    List<String> tags = session.selectOne("[...].getTagsById", 1);
    System.out.println("Tags: " + tags);

    List<List<String>> multiTags = session.selectList("[...].getTagsByName", "test");
    System.out.println("Tags: " + multiTags);
}

Протестировано на PostgreSQL 11 с драйвером JDBC версии 42.2.5 и следующими тестовыми данными:

select * from t;
 id |  name   |                tags                
----+---------+------------------------------------
  1 | test    | {Thriller,Drama}
  2 | my name | {Science-Fiction,Adventure,Horror}
  3 | test    | {Comedy,Adventure}
(3 rows)

... выдает:

Tags: [Thriller, Drama]
Tags: [[Thriller, Drama], [Comedy, Adventure]]
...