In questa puntata sull’utilizzo di MyBatis e Spring per connettersi ad un DB ed eseguire query, vedremo come eseguire, per l’appunto, query “avanzate1“.


Nei precedenti post avevamo visto come reperire tutte le tuple di una tabella oppure come reperire una tupla in base alla chiave. E se volessimo ottenere solamente una parte dei campi (diciamo, k degli n, con k < n)? E se volessimo fare una query per più campi? E se volessimo utilizzare il costrutto “where in”?

Vediamo come fare.

1) Reperire tuple in base a più campi

Nel file “ContattoMapper.xml” dobbiamo definire il solito snippet di codice in cui si specifica un parameterType di tipo java.util.Map:

<select id="selezionaPerNomeOCognome" resultType="contatto" parameterType="java.util.Map">
	select
	id, cognome, nome,
	telefono, email
	from contatto
	where nome = #{nome} or cognome = #{cognome}
</select>

Nel DAO, questa sarà la situazione:

@SuppressWarnings("unchecked")
@Override
public List<ContattoDTO> selezionaPerNomeOCognome(String nome, String cognome) {
	List<ContattoDTO> lst = null;

	try {
		Map<String, Object> parametri = new HashMap<String, Object>();
		parametri.put("nome", nome);
		parametri.put("cognome", cognome);

		lst = getSqlSession().selectList("selezionaPerNomeOCognome", parametri);
	} catch (Exception e) {
		log.error("Selezione fallita", e);
	}

	return lst;
}

Banalmente, nella mappa verranno mappati i campi tra nome colonna e parametro locale.

Il codice chiamante sarà questo:

List<ContattoDTO> contatti = dao.selezionaPerNomeOCognome("mario", "rossi");

2) Reperire k degli n campi tabella

Per riuscire in questo intento, dobbiamo specificare un DTO2 dedicato, ad esempio prendendo i soli campi “id” ed “email”, chiamando il DTO “EmailDTO”:

package com.toastedtech.mybatis.dto;

public class EmailDTO {
    Integer id;
    String email;

    @Override
    public String toString() {
        return "Mail [id=" + id + ", email=" + email + "]";
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}

In “ContattoMapper.xml” dobbiamo inserire il mapping in uscita, nonché la query:

<resultMap id="email" type="com.toastedtech.mybatis.dto.EmailDTO">
	<result property="id" column="id" />
	<result property="email" column="email" />
</resultMap>

<select id="selezionaIdMailPerNomeOCognome" resultMap="email" parameterType="java.util.Map">
	select
	id, email
	from contatto
	where nome = #{nome} or cognome = #{cognome}
</select>

Questa sarà invece la situazione del DAO:

@SuppressWarnings("unchecked")
@Override
public List<EmailDTO> selezionaIdMailPerNomeOCognome(String nome, String cognome) {
	List<EmailDTO> lst = null;

	try {
		Map<String, Object> parametri = new HashMap<String, Object>();
		parametri.put("nome", nome);
		parametri.put("cognome", cognome);

		lst = getSqlSession().selectList("selezionaIdMailPerNomeOCognome", parametri);
	} catch (Exception e) {
		log.error("Selezione fallita", e);
	}

	return lst;
}

E del codice chiamante:

List<EmailDTO> contatti = dao.selezionaIdMailPerNomeOCognome("mario", "rossi");

3) Utilizzare il costrutto “where in”

Per il where in è necessario specificare una lista di valori… supponiamo una serie di id, quindi una lista di interi.

In “ContattoMapper.xml” la situazione sarà:

<select id="selezionaPerIds" resultType="contatto" parameterType="java.util.Map">
	select
	id, cognome, nome,
	telefono, email
	from contatto
	where id in
	<foreach item="id" index="id" collection="id" open="(" separator="," close=")">
		#{id}
	</foreach>
</select>

Il foreach specifica tutti gli item della lista per il where in.

Nel DAO invece…

@SuppressWarnings("unchecked")
@Override
public List<ContattoDTO> selezionaPerIds(List<Integer> ids) {
	List<ContattoDTO> lst = null;

	try {
		Map<String, Object> parametri = new HashMap<String, Object>();
		parametri.put("id", ids);

		lst = getSqlSession().selectList("selezionaPerIds", parametri);
	} catch (Exception e) {
		log.error("Selezione fallita", e);
	}

	return lst;
}

Si può notare come venga settato il mapping “id” -> lista di id di tipo List<Integer>.

Il codice chiamante sarà ovviamente:

int i0 = 1;
int i1 = 3;
List<ContattoDTO> contatti = dao.selezionaPerIds(Arrays.asList(i0, i1));

Fine

Per ragioni di ordine, ho riorganizzato il progetto in questa maniera:

Il test case è tutto verde ovviamente :D

Questo è il codice sorgente del progetto: (mybatis-helloworld-eclipse-v0.3)

Buon divertimento :)

  1. Significato di avanzato preso in senso relativo :D
  2. Definizione di DTO su wiki