2010-12-14 9 views
6

Nella libreria di interfacciamento del database jOOQ, desidero aggiungere il supporto per i pacchetti Oracle (o DB2, ecc.). Ho già implementato il supporto di stored procedure/funzioni in cui ogni oggetto memorizzato è modellato come una classe Java generata. Ad esempio, questa funzione memorizzataMappatura tra pacchetti Oracle e pacchetti Java

CREATE FUNCTION f_author_exists (author_name VARCHAR2) RETURNS NUMBER; 

genererà una classe che può essere utilizzato in questo modo (si noti, ci sono anche un sacco di metodi di convenienza, questo esempio dimostra il disegno generale):

// 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 ragione per cui ho scelto una funzione ->- Java classe è perché le stored procedure consentono valori di ritorno complessi (diversi parametri OUT o IN OUT) che desidero essere in grado di recuperare uno dopo l'altro chiamando la procedura:

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

Ora questo disegno funziona correttamente con le funzioni/procedure memorizzate, dove sovraccarico non è possibile. All'interno dei pacchetti di Oracle (o DB2), tuttavia, posso avere diverse funzioni con lo stesso nome, come

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; 

Quando ho generare una classe per ogni funzione (o procedure), avrò gli scontri di denominazione con diversi FAuthorExists classi Java . Una soluzione zoppa consiste nell'aggiungere un indice al nome della classe, ad esempio FAuthorExists2, FAuthorExists3. Un'altra soluzione zoppa è generare una sorta di valore hash (o il valore stesso) dai nomi/tipi dei parametri direttamente nel nome classe, come FAuthorExistsVARCHAR2, FAuthorExistsVARCHAR2VARCHAR2. Nessuna soluzione è auspicabile per ovvi motivi.

Qualcuno ha una soluzione semplice a questo problema? O forse un'idea di un design complessivo migliore che non produrrebbe problemi di sovraccarico di questo nome di funzione?

Qualsiasi feedback apprezzato!

risposta

0

Non ho trovato nessun altro modo valido per risolvere questo problema rispetto all'utilizzo di un "indice di sovraccarico" sulle classi generate. Quindi, il pacchetto

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; 

produrranno queste classi:

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

Altre idee sarebbe solo causare nuovi conflitti in fase di generazione del codice, o in fase di esecuzione.

UPDATE: Nota, questa soluzione sembra anche l'unico a gestire situazioni come questa in modo corretto:

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; 

A quanto pare, questo tipo di sovraccarico è possibile in PL/SQL, anche.

3

tuo getReturnValue funzione potrebbe determinare in fase di chiamata che sovraccaricato la funzione di chiamare a seconda di quanti parametri di ingresso sono stati fissati - ma credo che finirà per essere più semplice se si tiene fede a qualcosa di simile setParam1 piuttosto che setName

+0

Il metodo 'execute()' effettua la chiamata effettiva. Il metodo è chiamato 'setName()' a causa dell'argomento function 'name'. L'ho risolto nell'esempio, per renderlo più chiaro. La tua idea non è cattiva. Sebbene, il problema è che se si ha un sovraccarico del nome della funzione con insiemi di argomenti molto distinti, allora potrebbe diventare difficile scoprire quale combinazione di argomenti sia possibile. Ma con i metodi di convenienza, potrebbe funzionare! +1 per l'idea di determinare la chiamata corretta al momento dell'esecuzione –

+0

@Lukas corrispondente ai tipi di argomenti piuttosto che ai nomi era ciò che intendevo per il mio suggerimento - pensavo che potesse essere più semplice. Penso che entrambi sarebbero possibili in linea di principio però. –

+0

È facile trovare una buona implementazione su come chiamare la funzione in base ai nomi degli argomenti/tipi/posizione. Ma la parte difficile è rendere il codice generato facile da usare per gli sviluppatori. Ecco perché uso il nome dell'argomento nei metodi generati –

0

È possibile superare i limiti di sovraccarico fornendo nomi univoci per ciascuna funzione.Ciò migliorerebbe anche la leggibilità del codice (questo è uno dei motivi why Golang doesn't have overloading). Ad esempio f_author_name_exists, f_author_name_country_exists.

Un altro modo, che complicherà le classi Java, consiste nel decidere in fase di esecuzione quale sia la procedura da chiamare, in base al quale è stato utilizzato il costruttore Java sovraccarico o quali setter sono stati utilizzati.

+0

Grazie per i tuoi suggerimenti. Come affermato nella domanda, si tratta di [jOOQ] (http://www.jooq.org), un'utility che genera codice sorgente per stored procedure, quindi non ho il controllo sulla procedura di sovraccarico del nome - che non uso t mente a tutti. Aggiunge l'espressività di un'API durante la creazione di metodi di convenienza. D'altra parte, a causa della presenza di parametri 'OUT', è difficile decidere quale procedura chiamare a runtime, se quella chiamata non è cablata al momento della generazione del codice ... –