簡體   English   中英

Mybatis對復雜對象參數中的整數列表進行迭代

[英]Mybatis foreach iteration over list of integers within a complex object parameter

我在Play Framework 2.3.6 Java項目中使用MyBatis 3.2.8。 我已經掙扎了幾天,迭代遍歷復雜對象參數中的MyBatis映射器的整數列表。 這是我的設置:

我在EventFilter.java中有一個名為EventFilter的類:

public class EventFilter {
private String beginDate;
private String endDate;
private List<Integer> closestCountry;
private List<Integer> territorialWaterStatus;
private List<Integer> vesselCountry;
private String closestCountryInClause;
private String territorialWaterStatusInClause;
private String vesselCountryInClause;

public EventFilter() { }

public EventFilter(JsonNode jsonNode){
    this.beginDate = jsonNode.get("beginDate").asText();
    this.endDate = jsonNode.get("endDate").asText();
    this.closestCountry = JsonHelper.arrayNodeToIntegerList((ArrayNode) jsonNode.get("closestCountry"));
    this.territorialWaterStatus = JsonHelper.arrayNodeToIntegerList((ArrayNode) jsonNode.get("territorialWaterStatus"));
    this.vesselCountry = JsonHelper.arrayNodeToIntegerList((ArrayNode) jsonNode.get("vesselCountry"));
}

public String getBeginDate() {
    return beginDate;
}

public void setBeginDate(String beginDate) {
    this.beginDate = beginDate;
}

public String getEndDate() {
    return endDate;
}

public void setEndDate(String endDate) {
    this.endDate = endDate;
}

public List<Integer> getTerritorialWaterStatus() {
    if(this.territorialWaterStatus.size() > 0) {
        return territorialWaterStatus;
    } else {
        return null;
    }
}

public void setTerritorialWaterStatus(List<Integer> territorialWaterStatus) {
    this.territorialWaterStatus = territorialWaterStatus;
}

public List<Integer> getClosestCountry() {
    if(this.closestCountry.size() > 0) {
        return closestCountry;
    } else {
        return null;
    }
}

public void setClosestCountry(List<Integer> closestCountry) {
    this.closestCountry = closestCountry;
}

public List<Integer> getVesselCountry() {
    if(this.vesselCountry.size() > 0) {
        return vesselCountry;
    } else {
        return null;
    }
}

public void setVesselCountry(List<Integer> vesselCountry) {
    this.vesselCountry = vesselCountry;
}

}

這在我的mybatis配置文件中被引用為類型別名:

<configuration>

<typeAliases>
    <typeAlias type="models.Event" alias="Event"/>
    <typeAlias type="models.EventFilter" alias="EventFilter"/>
    <typeAlias type="models.Country" alias="Country"/>
</typeAliases>

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="org.postgresql.Driver"/>
            <property name="url" value="jdbc:postgresql://localhost:5432/mpmap"/>
            <property name="username" value="postgres"/>
            <property name="password" value="dbpw"/>
        </dataSource>
    </environment>
</environments>

<mappers>
    <mapper resource="EventMapper.xml"/>
</mappers>
</configuration>

我有一個mapper,它以EventFilter對象作為參數。 然后應檢查是否設置了beginDate,endDate,nearestCountry,vesselCountry和territorialWaterStatus。 如果是,它將它們用於WHERE子句:

<select id="getEventsWithFilter" resultType="Event" resultMap="EventResult">
    SELECT ev.id, to_char(ev.occurred_on, 'YYYY-MM-DD') AS occurred_on_date,
        to_char(ev.occurred_on, 'HH24:MI:SS') AS occurred_on_time,
        ST_X(ev.location) AS longitude, ST_Y(ev.location) AS latitude,
        COALESCE(co01.name, 'Unspecified') AS closest_country,
        COALESCE(co02.name, 'Unspecified') AS territorial_water_status,
        COALESCE(co03.name, 'Unspecified') AS vessel_flag_country
    FROM event AS ev
    LEFT JOIN country AS co01
        ON co01.cow_id = ev.location_closest_country_id
    LEFT JOIN country AS co02
        ON co02.cow_id = ev.location_water_status_country_id
    LEFT JOIN country AS co03
        ON co03.cow_id = ev.vessel_flag_country_id
    <where>
        <if test="#{eventFilter.beginDate} != null and #{eventFilter.endDate} != null">
            ev.occurred_on &gt;= #{eventFilter.beginDate}::timestamp AND ev.occurred_on &lt;= #{eventFilter.endDate}::timestamp
        </if>
        <if test="#{eventFilter.closestCountry} != null">
            AND ev.location_closest_country_id IN
            <foreach item="id" index="index" collection="#{eventFilter.closestCountry}" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
        <if test="#{eventFilter.territorialWaterStatus} != null">
            AND ev.location_water_status_country_id IN
            <foreach item="id" index="index" collection="#{eventFilter.territorialWaterStatus}" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
        <if test="#{eventFilter.vesselCountry} != null">
            AND ev.vessel_flag_country_id IN
            <foreach item="id" index="index" collection="#{eventFilter.vesselCountry}" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
    </where>
    ORDER BY ev.occurred_on ASC;
</select>

我將映射器鏈接到一個接口,如下所示:

    public List<Event> getEventsWithFilter(@Param("eventFilter") EventFilter eventFilter);

我用MybatisMapper輔助類調用它來生成我的會話,如下所示:

public static List<Event> getEvents(EventFilter eventFilter) {
    MybatisMapper mapper = new MybatisMapper();
    SqlSession session = mapper.getSession();
    EventMapper eventMapper = session.getMapper(EventMapper.class);

    List<Event> events;

    List<Integer> li = eventFilter.getClosestCountry();

    try {
        events = eventMapper.getEventsWithFilter(eventFilter);
    } finally {
        session.close();
    }

    return events;
}

問題:

beginDate和endDate自己完全正常工作。 但是我對整數列表有以下問題:

  1. 檢查列表是否為null的if語句似乎被忽略,或者當它應該為false時評估為true。
  2. 整數列表似乎作為null傳遞給IN子句。
  3. 如果我注釋掉整數列表的IN子句,只是注釋到beginDate和endDate,它就可以正常工作。 但是,如果我保留整數列表IN子句,查詢不會失敗,但它返回一個空集,就像說“WHERE列IN()”。

這是執行映射器/查詢時由Play和Mybatis打印的控制台日志記錄,以及EventFilter打印其內容。 它們有點冗長所以我把它們放在pastebin中:

這比我想要的要長一點,但提前感謝任何幫助或建議。

我終於搞定了。 我最不得不改變的是在我的XML映射器中尋址參數列表而沒有周圍的花括號。

所以代替:

 <if test="#{eventFilter.closestCountry} != null">
        AND ev.location_closest_country_id IN
        <foreach item="id" index="index" collection="#{eventFilter.closestCountry}" open="(" separator="," close=")">
            #{id}
        </foreach>
    </if>

它應該是:

<if test="eventFilter.closestCountry != null">
            AND ev.location_closest_country_id IN
            <foreach item="id" index="index" collection="eventFilter.closestCountry" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>

這很奇怪,因為傳遞對象中的尋址字符串可以使用任何一種方法 - 即#{eventFilter.beginDate}與eventFilter.beginDate相同。

一個非常微妙的區別,但我希望它可以幫助別人節省一些時間。

試試這個

<if test="eventFilter.closestCountry != null">
        AND ev.location_closest_country_id IN
        <foreach item="id" index="index" collection="eventFilter.closestCountry" open="(" separator="," close=")">
            ${id}
        </foreach>
    </if>

我正在使用MyBatis v.3.4.6。

我的情況:

@Mapper
public interface CorsoMapper {
    List<CorsoEntity> elenco(Filtro filtro);
}


public class Filtro implements Serializable {
    private static final long serialVersionUID = -8357822764110641974L;

    private String codice;
    private List<String> codici;

    public String getCodice() {
        return codice;
    }

    public void setCodice(String codice) {
        this.codice = codice;
    }

    public List<String> getCodici() {
        return codici;
    }

    public void setCodici(List<String> codici) {
        this.codici = codici;
    }
}

SQL:

<select id="elencoCorsi" parameterType="it.blabla.Filtro" resultMap="corsoMap">
    AND CODICI IN
    <foreach item="c" collection="codici" open="(" separator="," close=")">
       #{c}
    </foreach>
</select>

它不使用“索引”屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM