我正在使用(旧版)Java应用和数据库,我需要将MyBatis多列映射到单个数组属性
我的查询类似于
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对象
任何提示?
答案 0 :(得分:4)
您也可以实现BaseTypeHandler接口,并且在getNullableResult方法中,ResultSet变量可供您使用。因此,您可以轻松获取所需的所有列并将它们放入阵列。
答案 1 :(得分:2)
您说您无法修改查询 - 如果这意味着您无法更改SQL但您可以更改MyBatis映射,那么我建议您使用MyBatis ObjectFactory。您定义DefaultObjectFactory
的子类并覆盖create
方法。 ObjectFactory接收您在MyBatis ResultMap中指定为“构造函数args”的参数。
您的MyBatis映射现在将指定price字段是构造函数参数,即使它们不是真的。这只是将原始数据传递给您自己的处理程序/工厂的便捷方式。
<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 config.xml中来覆盖MyBatis的默认ObjectFactory:
<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。
答案 2 :(得分:1)
另一种选择是使用创建一个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