2.3.2.4 Estructurat
Estructurat
En el cas dels tipus definits per l'usuari en PosgreSQL, lamentablement les coses no funcionen tan bé. I és una pena, perquè si puguérem ens estalviaríem molta de la feina de mapatge fent la correspondència entre els tipus definits en PostgreSQL i classes definides en Java.
Els mètodes que s'utilitzaran ara són getObject(index) del ResultSet, i per a poder guardar el setObject(index,objecte) del PreparedStatement.
Podem accedir a l'adreça que és del tipus estructurat definit per nosaltres (amb carrer, codi postal i població).
Per tant sembla que va bé la cosa, però no. El problema és accedir a les dades internes de l'objecte. Si puguérem fer una conversió entre el tipus de dades definit en PostgreSQL (t_adreca) i una classe definida en Java que continga 3 propietats per al carrer, el codi postal i la població, ja ho tindríem. Però hi ha documentació per Internet que diu que no es pot fer. És a dir, el següent programa (suposem que tenim una classe anomenada Adreca que consta de 3 strings) :
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Prova7_2 {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://89.36.214.106:5432/rxx";
Connection con = DriverManager.getConnection(url, "rxx", "rxx");
ResultSet rs = con.createStatement().executeQuery("SELECT nom,adreca FROM persona4 ORDER BY nom");
while (rs.next()) {
System.out.println("Adreça de " + rs.getString(1) + ": ");
Adreca adr = (Adreca) rs.getObject(2);
System.out.println(adr.getCarrer() + ". " + adr.getCodipostal() + " (" +adr.getPoblacio() + ")");
}
rs.close();
con.close();
}
}
dóna el següent error:
Exception in thread "main" java.lang.ClassCastException: org.postgresql.util.PGobject cannot be cast to Exemples.Adreca
at Exemples.Prova7_2.main(Prova7_2.java:16)
És a dir, no s'ha pogut convertir l'objecte agafat des de PostgreSQL a la classe definida en Java (recordeu que suposem que tenim una classe anomenada Adreca que consta de 3 strings).
Es pot arreglar, però l'esforç segurament no valdrà la pena.
La manera que he tingut de solucionar-lo ha estat buscar un altre driver JDBC que sí que ens permet fer una conversió entre els tipus que venen des de PostgreSQL. Aquest nou driver s'anomena pgjdbc-ng i el podeu trobar a la següent adreça:
https://impossibl.github.io/pgjdbc-ng
El següent programa sí que funcionarà. Observeu com la manera de connectar és lleugerament diferent (mreu la URL). Hem utilitzat un objecte de tipus Struct per a poder arreplegar el resultat.import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Struct;
public class Prova7_3 {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
String url = "jdbc:pgsql://89.36.214.106:5432/rxx";
Connection con = DriverManager.getConnection(url, "rxx", "rxx");
ResultSet rs = con.createStatement().executeQuery("SELECT nom,adreca FROM persona4 ORDER BY nom");
while (rs.next()) {
System.out.println("Adreça de " + rs.getString(1) + ": ");
Struct adr = (Struct)rs.getObject(2);
if (adr != null)
System.out.println(adr.getAttributes()[0] + ". " + adr.getAttributes()[1] + " (" + adr.getAttributes()[2] + ")");
}
rs.close();
con.close();
}
}
I produiria el següent resultat:
Adreça de Albert:
C/Major, 7. 12001 (Castelló)
Adreça de Bernat:
null. null (Castelló)
Adreça de Clàudia:
null. null (Castelló)
Adreça de David:
Adreça de Eva:
Adreça de Ferran:
En aquest exemple fem la reconversió completa de t_adreca a Adreca. En aquesta classe, Adreca, implementem un constructor que agafa com a paràmetre un Struc (que ha estat la manera de salvar l'inconvenient en l'exemple anterior), i inicialitza les propietats a partir d'ell;
import java.sql.SQLException;
import java.sql.Struct;
public class Adreca {
private String carrer = null;
private String codipostal = null;
private String poblacio = null;
public Adreca() {
}
public Adreca(String c, String cp, String p) {
this.carrer = c;
this.codipostal = cp;
this.poblacio = p;
}
public Adreca(Struct t_adr) throws SQLException {
if (t_adr != null) {
this.carrer = (String) t_adr.getAttributes()[0];
this.codipostal = (String) t_adr.getAttributes()[1];
this.poblacio = (String) t_adr.getAttributes()[2];
}
}
public String getCarrer() {
return carrer;
}
public void setCarrer(String carrer) {
this.carrer = carrer;
}
public String getCodipostal() {
return codipostal;
}
public void setCodipostal(String codipostal) {
this.codipostal = codipostal;
}
public String getPoblacio() {
return poblacio;
}
public void setPoblacio(String poblacio) {
this.poblacio = poblacio;
}
}
Això ens permet fer el següent programa que ara sí que ens funcionarà. En compte de fer un cast utilitzem el constructor, i igual queda còmode. Hem aprofitat per traure només aquells que tenen alguna cosa en l'adreça.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Struct;
public class Prova7_4 {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
String url = "jdbc:pgsql://89.36.214.106:5432/rxx";
Connection con = DriverManager.getConnection(url, "rxx", "rxx");
ResultSet rs = con.createStatement().executeQuery("SELECT nom,adreca FROM persona4 ORDER BY nom");
while (rs.next()) {
if (rs.getObject(2) != null) {
System.out.println("Adreça de " + rs.getString(1) + ": ");
Adreca adr = new Adreca((Struct) rs.getObject(2));
System.out.println(adr.getCarrer() + ". " + adr.getCodipostal() + " (" + adr.getPoblacio() + ")");
}
}
rs.close();
con.close();
}
}
Recordeu que heu d'incorporar el driver pgjdbc-ng
El que sí que podem fer sense problemes des del driver normal és accedir als camps del tipus estructurat des de SQL. Però açò ens obliga en certa manera a dur el mapatge manual.
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Prova7_5 {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://89.36.214.106:5432/rxx";
Connection con = DriverManager.getConnection(url, "rxx", "rxx");
ResultSet rs = con.createStatement().executeQuery(
"SELECT nom,(adreca).carrer,(adreca).codipostal,(adreca).poblacio FROM persona4 ORDER BY nom");
while (rs.next()) {
System.out.println("Adreça de " + rs.getString(1) + ": ");
System.out.println(rs.getString(2) + ". CP: " + rs.getString(3) + " (" + rs.getString(4) + ")");
}
}
}
Mirem un altre exemple per a accedir als telèfons. Recordem que telefons és un array de t_telefon, per tant estem barrejant un array amb un tipus estructurat. Podem agafar bé l'array (col·loquem l'array en un ResultSet per mig de getResultSet, que ens dóna tants registres com elements de l'array. En cada registre tenim en el primer camp el número d'ordre, i en el segon el valor (que en el nostre cas és t_telefon)
Llicenciat sota la Llicència Creative Commons Reconeixement NoComercial CompartirIgual 2.5