2010-12-14 101 views
6

Dans ma bibliothèque d'interfaçage de base de données jOOQ, je souhaite ajouter un support pour les packages Oracle (ou DB2, etc.). J'ai déjà implémenté la procédure stockée/support de fonction où chaque objet stocké est modélisé comme une classe Java générée. Par exemple, cette fonction stockéeMappage entre packages Oracle et Java

CREATE FUNCTION f_author_exists (author_name VARCHAR2) RETURNS NUMBER; 

va générer une classe qui peut être utilisé comme ceci (note, il y a aussi beaucoup de méthodes pratiques, cet exemple montre que la conception générale):

// A new "function call instance". The function needs to be instanciated 
// once per call 
FAuthorExists f = new FAuthorExists(); 

// Set the function parameters on the call instance and call it 
f.setAuthorName("Paulo"); 
f.execute(connection); 

// Fetch the result from the function call instance 
BigDecimal result = f.getReturnValue(); 

La raison pour laquelle j'ai choisi un mappage La fonction SQL ->Classe Java est que les procédures stockées autorisent des valeurs de retour complexes (plusieurs paramètres OUT ou IN OUT) que je veux pouvoir extraire une par une après l'appel de la procédure:

p.getOutParam1(); 
p.getOutParam2(); 

Maintenant, cette conception fonctionne très bien avec des fonctions/procédures stockées, où la surcharge est impossible. Au sein de packages d'Oracle (ou DB2 pour), mais je peux avoir plusieurs fonctions avec le même nom, comme

CREATE PACKAGE my_package IS 
    FUNCTION f_author_exists (name VARCHAR2) RETURNS NUMBER; 
    FUNCTION f_author_exists (name VARCHAR2, country VARCHAR2) RETURNS NUMBER; 
END my_package; 

Quand je produis une classe par fonction (ou procédure), je vais avoir des affrontements de noms avec plusieurs FAuthorExists classes Java . Une solution boiteuse consiste à ajouter un index au nom de classe, tel que FAuthorExists2, FAuthorExists3. Une autre solution boiteuse consiste à générer une sorte de valeur de hachage (ou la valeur elle-même) à partir des noms/types de paramètres directement dans le nom de classe, tel que FAuthorExistsVARCHAR2, FAuthorExistsVARCHAR2VARCHAR2. Aucune solution n'est souhaitable pour des raisons évidentes.

Quelqu'un at-il une solution simple à ce problème? Ou peut-être une idée d'une meilleure conception globale qui ne produirait pas de tels problèmes de surcharge de nom de fonction?

Tout commentaire apprécié!

Répondre

0

Je n'ai trouvé aucun autre moyen viable de résoudre ce problème que d'utiliser un "index de surcharge" sur les classes générées. Par conséquent, le paquet

CREATE PACKAGE my_package IS 
    FUNCTION f_author_exists (name VARCHAR2) RETURNS NUMBER; 
    FUNCTION f_author_exists (name VARCHAR2, country VARCHAR2) RETURNS NUMBER; 
END my_package; 

PRODUIRONT ces classes:

public class FAuthorExists1 { /* ... */ } 
public class FAuthorExists2 { /* ... */ } 

D'autres idées déclenchait de nouveaux conflits au moment de génération de code, ou lors de l'exécution.

MISE À JOUR: Remarque, cette solution semble aussi le seul à gérer des situations comme celle-ci correctement:

CREATE PACKAGE my_package IS 
    PROCEDURE f_author_exists (name VARCHAR2); 
    PROCEDURE f_author_exists (name CHAR); 
    PROCEDURE f_author_exists (name CHAR, country OUT VARCHAR2); 
END my_package; 

Comme il semble, ce genre de surcharge est possible en PL/SQL, aussi.

3

Votre fonction getReturnValue pourrait déterminer au moment de l'appel dont la fonction surchargée d'appeler en fonction du nombre de paramètres d'entrée ont été mis - mais je pense que ça va finir par être plus simple si vous vous en tenez à quelque chose comme setParam1 plutôt que setName

+0

La méthode 'execute()' effectue l'appel réel. La méthode est appelée 'setName()' à cause de l'argument de la fonction 'name'. J'ai corrigé cela dans l'exemple, pour le rendre plus clair. Votre idée n'est pas mauvaise. Bien que, le problème est si vous avez la surcharge de nom de fonction avec des ensembles d'arguments très distincts, alors il peut devenir déroutant de découvrir, quelle combinaison d'arguments est possible. Mais avec les méthodes de commodité, cela pourrait effectivement fonctionner! +1 pour l'idée de déterminer l'appel correct à l'exécution –

+0

@Lukas correspondant à des types d'arguments plutôt que des noms était ce que je voulais dire par ma suggestion - je pensais que ce pourrait être plus simple. Je pense que ce serait possible en principe cependant. –

+0

Il est facile de trouver une bonne implémentation sur comment appeler la fonction en fonction des noms/types/positions des arguments. Mais la partie difficile est de rendre le code généré facile à utiliser pour les développeurs. C'est pourquoi j'utilise le nom de l'argument dans les méthodes générées –

0

Vous pouvez surmonter les limites de la surcharge en attribuant des noms uniques à chaque fonction.Cela améliorerait également la lisibilité du code (c'est l'une des raisons why Golang doesn't have overloading). Par exemple, f_author_name_exists, f_author_name_country_exists. Une autre façon, qui compliquera les classes Java, est de décider au moment de l'exécution quelle procédure appeler, en fonction du constructeur Java surchargé ou des paramètres utilisés.

+0

Merci pour vos astuces. Comme indiqué dans la question, il s'agit de [jOOQ] (http://www.jooq.org), un utilitaire qui génère du code source pour les procédures stockées, donc je n'ai pas de contrôle sur la surcharge des noms de procédures - ce que je ne fais pas. Ça ne me dérange pas du tout. Il ajoute à l'expressivité d'une API lors de la création de méthodes de commodité. D'autre part, en raison de la présence de paramètres 'OUT', il est difficile de décider quelle procédure appeler lors de l'exécution, si cet appel n'est pas câblé au moment de la génération du code ... –