2012-08-03 82 views
3

我有(傳統)的Java應用程序和數據庫工作,我需要與MyBatis的多個列映射到一個數組屬性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對象

任何提示?

回答

4

也可以實現BaseTypeHandler接口,並在getNullableResult方法中爲您提供ResultSet變量。因此,您可以輕鬆獲取所需的所有列,並將它們放入陣列。

1

你說你不能修改查詢 - 如果這意味着你不能改變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; 
    } 
} 

如果您還想要/需要有價格構造函數的附加參數(如id),然後在映射的<constructor>部分中指定這些參數,並將其傳入到你的PriceObjectFactory。

+0

然後你回答。我認爲我太簡單了。我有幾個colums /數組的「組」。在這種情況下,我認爲將所有這些字段映射爲構造器參數可能有點過於冗長。 – pbanfi 2012-08-06 06:34:09

+0

我澄清了我的問題:-) – pbanfi 2012-08-06 07:16:26

+0

我在其他選項上工作,找不到一個簡單的方法。這在MyBatis的甜蜜點中不是問題,據我所知,如何使用它。我在下面提供了另一個選項,但總的來說,我更喜歡這裏的答案,因爲您可以使用Mapper類,而不僅僅是xml。你只需要在你的XML的''部分添加你需要的任何東西。它是「冗長的」,因爲你必須直接處理它,就像你在做純JDBC一樣,但是你可以把它封裝在一個地方(下面的工廠或ResultHandler),其餘的代碼沒有處理它。 – quux00 2012-08-07 00:58:55

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