Créer des objets qui implémentent java.sql.SQLData
. Dans ce scénario, créez TEnclosure
et TAnimal
classes, qui implémentent toutes deux SQLData
.
Juste pour info, dans les nouvelles versions d'Oracle JDBC, des types tels que oracle .sql.TABLEAU
sont obsolètes au profit de java.sql
les types. Bien que je ne sois pas sûr de savoir comment écrire un tableau (décrit ci-dessous) en utilisant uniquement java.sql
API.
Lorsque vous implémentez readSQL()
vous lisez les champs dans l'ordre. Vous obtenez un java.sql.Array
avec sqlInput.readArray()
. Donc TEnclosure.readSQL()
ressemblerait à ceci.
@Override
public void readSQL(SQLInput sqlInput, String s) throws SQLException {
id = sqlInput.readBigDecimal();
name = sqlInput.readString();
Array animals = sqlInput.readArray();
// what to do here...
}
Remarque :readInt()
existe également, mais Oracle JDBC semble toujours fournir BigDecimal
pour NUMBER
Vous remarquerez que certaines API telles que java.sql.Array
avoir des méthodes qui prennent une carte de type Map<String, Class<?>>
Il s'agit d'un mappage des noms de type Oracle à leur classe Java correspondante implémentant SQLData
(ORAData
peut fonctionner aussi ?).
Si vous appelez simplement Array.getArray()
, vous obtiendrez Struct
objets sauf si le pilote JDBC connaît vos mappages de types via Connection.setTypeMap(typeMap)
. Cependant, la définition de typeMap sur la connexion n'a pas fonctionné pour moi, j'utilise donc getArray(typeMap)
Créez votre Map<String, Class<?>> typeMap
quelque part et ajoutez des entrées pour vos types :
typeMap.put("T_ENCLOSURE", TEnclosure.class);
typeMap.put("T_ANIMAL", TAnimal.class);
Dans un SQLData.readSQL()
implémentation, appelez sqlInput.readArray().getArray(typeMap)
, qui renvoie Object[]
où l'Object
entrées ou de type TAnimal
.
Bien sûr le code à convertir en List<TAnimal>
devient fastidieux, alors utilisez simplement cette fonction utilitaire et ajustez-la à vos besoins en ce qui concerne la politique de liste nulle ou vide :
/**
* Constructs a list from the given SQL Array
* Note: this needs to be static because it's called from SQLData classes.
*
* @param <T> SQLData implementing class
* @param array Array containing objects of type T
* @param typeClass Class reference used to cast T type
* @return List<T> (empty if array=null)
* @throws SQLException
*/
public static <T> List<T> listFromArray(Array array, Class<T> typeClass) throws SQLException {
if (array == null) {
return Collections.emptyList();
}
// Java does not allow casting Object[] to T[]
final Object[] objectArray = (Object[]) array.getArray(getTypeMap());
List<T> list = new ArrayList<>(objectArray.length);
for (Object o : objectArray) {
list.add(typeClass.cast(o));
}
return list;
}
Écrire des tableaux
Comprendre comment écrire un tableau était frustrant, les API Oracle nécessitent une connexion pour créer un tableau, mais vous n'avez pas de connexion évidente dans le contexte de writeSQL(SQLOutput sqlOutput)
. Heureusement, ce blog
a un truc/hack pour obtenir le OracleConnection
, que j'ai utilisé ici.
Lorsque vous créez un tableau avec createOracleArray()
vous spécifiez le type de liste (T_ARRAY_ANIMALS
) pour le nom du type, PAS le type d'objet singulier.
Voici une fonction générique pour écrire des tableaux. Dans votre cas, listType
serait "T_ARRAY_ANIMALS"
et vous passeriez dans List<TAnimal>
/**
* Write the list out as an Array
*
* @param sqlOutput SQLOutput to write array to
* @param listType array type name (table of type)
* @param list List of objects to write as an array
* @param <T> Class implementing SQLData that corresponds to the type listType is a list of.
* @throws SQLException
* @throws ClassCastException if SQLOutput is not an OracleSQLOutput
*/
public static <T> void writeArrayFromList(SQLOutput sqlOutput, String listType, @Nullable List<T> list) throws SQLException {
final OracleSQLOutput out = (OracleSQLOutput) sqlOutput;
OracleConnection conn = (OracleConnection) out.getSTRUCT().getJavaSqlConnection();
conn.setTypeMap(getTypeMap()); // not needed?
if (list == null) {
list = Collections.emptyList();
}
final Array array = conn.createOracleArray(listType, list.toArray());
out.writeArray(array);
}
Remarques :
- À un moment donné, j'ai pensé
setTypeMap
était nécessaire, mais maintenant, lorsque je supprime cette ligne, mon code fonctionne toujours, donc je ne sais pas si c'est nécessaire. - Je ne sais pas si vous devez écrire null ou un tableau vide, mais j'ai supposé que le tableau vide est plus correct.
Conseils sur les types Oracle
- Oracle met tout en majuscules, donc tous les noms de type doivent être en majuscules.
- Vous devrez peut-être spécifier
SCHEMA.TYPE_NAME
si le type n'est pas dans votre schéma par défaut. - N'oubliez pas d'
grant execute
sur les types si l'utilisateur avec lequel vous vous connectez n'est pas le propriétaire.
Si vous avez exécuté sur le package, mais pas sur le type,getArray()
lèvera une exception lorsqu'il essaiera de rechercher des métadonnées de type.
Printemps
Pour les développeurs utilisant Spring , vous pouvez consulter Spring Data JDBC Extensions
, qui fournit SqlArrayValue
et SqlReturnArray
, qui sont utiles pour créer un SimpleJdbcCall
pour une procédure qui prend un tableau comme argument ou retourne un tableau.
Chapitre 7.2.1 Définition des valeurs ARRAY à l'aide de SqlArrayValue pour un paramètre IN explique comment appeler des procédures avec des paramètres de tableau.