我在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 >= #{eventFilter.beginDate}::timestamp AND ev.occurred_on <= #{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自行完成。但是我对整数列表有以下问题:
这是执行映射器/查询时由Play和Mybatis打印的控制台日志记录,以及EventFilter打印其内容。它们有点冗长所以我把它们放在pastebin中:
这比我想要的要长一点,但要提前感谢任何帮助或建议。
答案 0 :(得分:5)
我终于开始工作了。我最不得不改变的是在我的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相同。
一个非常微妙的区别,但我希望它可以帮助别人节省一些时间。
答案 1 :(得分:2)
试试这个
<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>
答案 2 :(得分:0)
我正在使用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>
它无需使用“ index”属性即可工作。