3

我正在使用(旧版)java 应用程序和数据库,我需要将 MyBatis 多列映射到单个 Array 属性

我的查询类似于

select price1, price2, price3, qty1, qty2,qty3 ... from table where ....

对应的pojo是

public class Price{
    double[] prices = new double[3]
    int[] quantity = new int[3]
    public double[] getPrices(){}
    public void setPrices(double[] prices){...}
    public int[] getQty(){...}
    public void setQty(int[] quantities){...}
    ....
}

不幸的是,我既不能修改查询也不能修改 java 对象

任何提示?

4

3 回答 3

4

您也可以实现 BaseTypeHandler 接口,并在 getNullableResult 方法中为您提供 ResultSet 变量。因此,您可以轻松获取所需的所有列并将它们放入 Array。

于 2012-10-29T16:18:06.043 回答
2

另一种选择是使用创建一个 ResultHandler,这是一个 MyBatis 接口,您可以将其传递给SqlSession#select方法来处理从查询返回的数据。

以下是如何使用它来解决您的问题。

首先定义一个 PriceResultHandler,如下所示:

import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;

public class PriceResultHandler implements ResultHandler {

  // keep a list, assuming you have multiple Price objects to handle
  List<Price> lp = new ArrayList<Price>();

  @Override
  public void handleResult(ResultContext rc) {
    // the result object is map with column names mapped to values like so:
    // {price1=11.32, qty1=15500, price2=2.62, qty2=234, etc.}

    HashMap<?,?> m = (HashMap<?,?>) rc.getResultObject();
    Price p = new Price();
    double[] prices = new double[]{ ((Number)m.get("price1")).doubleValue(),
                                    ((Number)m.get("price2")).doubleValue(),
                                    ((Number)m.get("price3")).doubleValue() };
    int[] qty = new int[]{ ((Number)m.get("qty1")).intValue(),
                           ((Number)m.get("qty2")).intValue(),
                           ((Number)m.get("qty3")).intValue() };
    p.setPrices(prices);
    p.setQty(qty);
    lp.add(p);
  }


  public List<Price> getPrices() {
    return lp;
  }

ResultHandler 接收 HashMap 的原因是您将像这样设置映射:

<select id="getPrices" resultType="hashmap">
  SELECT price1, price2, price3, qty1, qty2, qty3 
  FROM table 
  WHERE ...
</select>

然后在 Java 代码中调用它,如下所示:

PriceResultHandler rh = new PriceResultHandler();
session.select("getPrices", rh);
// or
session.select("getPrices", arg, rh);
// where arg is a value to pass to the getPrices query mapping

Price p = rh.getPrices().get(0);

这个模型与我在另一个答案中给出的另一个选项的工作量大致相同。MyBatis 只是简单地将 JDBC ResultSet 映射到一个 Map 中,然后你用它来创建你认为合适的域对象。

这种方法的一个警告是您必须处理地图中列名的区分大小写问题。你不能通过 MyBatis 来控制它。这取决于底层 JDBC 驱动程序的行为:https ://stackoverflow.com/a/11732674/871012

于 2012-08-07T00:48:17.640 回答
2

你说你不能修改查询——如果这意味着你不能改变 SQL 但你可以改变你的 MyBatis 映射,那么我推荐使用 MyBatis ObjectFactory。您定义一个子类DefaultObjectFactory并覆盖该create方法。ObjectFactory 接收您在 MyBatis ResultMap 中指定为“构造函数参数”的参数。

您的 MyBatis 映射现在将指定价格字段是构造函数参数,即使它们不是真的。这只是将原始数据传递给您自己的处理程序/工厂的一种便捷方式。

<resultMap id="priceResultMap" type="Price">
  <constructor>
    <arg column="price1" javaType="double"/>
    <arg column="price2" javaType="double"/>
    <arg column="price3" javaType="double"/>
    <arg column="qty1" javaType="int"/>
    <arg column="qty2" javaType="int"/>
    <arg column="qty3" javaType="int"/>
  </constructor>
</resultMap>

<select id="getPrice" resultMap="priceResultMap">
  SELECT price1, price2, price3, qty1, qt2, qty3 ...
  FROM table 
  WHERE ...
</select>

你覆盖 MyBatis 的默认 ObjectFactory,把它放在你的 mybatis config.xml 中:

<objectFactory type="net.foo.bar.PriceObjectFactory"/>

然后 PriceObjectFactory 看起来像这样:

import org.apache.ibatis.reflection.factory.DefaultObjectFactory;

public class PriceObjectFactory extends DefaultObjectFactory {

  private static final long serialVersionUID = 3627013739044L;

  @Override
  public <T> T create(final Class<T> type, final List<Class<?>> ctorArgTypes,
                      final List<Object> ctorArgs) {
    if (type.equals(Price.class)) {
      return this.<T>createPrice(ctorArgs);
    } else {
      // let MyBatis handle the other object types as it normally does
      return super.<T>create(type, ctorArgTypes, ctorArgs);
    }
  }

  private <T> T createPrice(final List<Object> ctorArgs) {
    final int expSize = 6;
    if (ctorArgs.size() != expSize) {
      throw new IllegalArgumentException("Expected " + expSize +
                                         " ctor args for Price class");
    }

    // construct with no arg ctor
    final Price p = new Price();
    double[] prices = new double[]{ ((Number)ctorArgs.get(0)).doubleValue(), 
                                    ((Number)ctorArgs.get(1)).doubleValue(),
                                    ((Number)ctorArgs.get(2)).doubleValue()};
    int[] qty = new int[]{ ((Number)ctorArgs.get(3)).intValue(),
                           ((Number)ctorArgs.get(4)).intValue(),
                           ((Number)ctorArgs.get(5)).intValue() };
    p.setPrices(prices);
    p.setQty(qty);

    @SuppressWarnings("unchecked")
    final T t = (T) p;
    return t;
  }
}

如果您还希望/需要为 Price 构造函数提供其他参数(如 id),则<constructor>在映射部分中指定这些参数,它也将被传递到您的 PriceObjectFactory。

于 2012-08-05T13:56:47.370 回答