2010-12-14 14 views
6

En mi biblioteca de interfaces de bases de datos jOOQ, me gustaría agregar soporte para paquetes Oracle (o DB2, etc.). Ya he implementado el procedimiento almacenado/soporte de funciones donde cada objeto almacenado se modela como una clase Java generada. Por ejemplo, esta función almacenadaAsignación entre paquetes Oracle y paquetes Java

CREATE FUNCTION f_author_exists (author_name VARCHAR2) RETURNS NUMBER; 

generará una clase que puede ser utilizado como esto (nota, también hay un montón de métodos de conveniencia, este ejemplo demuestra el diseño general):

// 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(); 

El motivo por el que elegí una función de SQL ->Java Class es porque los procedimientos almacenados permiten valores de retorno complejos (varios parámetros OUT o IN OUT) que deseo poder buscar uno por uno después de llamar al procedimiento:

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

Ahora este diseño funciona bien con funciones/procedimientos almacenados, donde sobrecarga no es posible. Dentro de los paquetes de Oracle (o DB2 de), sin embargo, puedo tener varias funciones con el mismo nombre, como

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; 

Cuando genero una clase por cada función (o procedimiento), que tendrá choques de nombres con varios FAuthorExists clases Java . Una solución incorrecta es agregar un índice al nombre de la clase, como FAuthorExists2, FAuthorExists3. Otra solución coja es generar algún tipo de valor hash (o el valor mismo) de los nombres/tipos de parámetros directamente en el nombre de clase, como FAuthorExistsVARCHAR2, FAuthorExistsVARCHAR2VARCHAR2. Ninguna de las soluciones es deseable por razones obvias.

¿Alguien tiene una solución simple a este problema? ¿O tal vez una idea de un mejor diseño general que no produciría problemas de sobrecarga de nombre de función?

¡Cualquier comentario apreciado!

Respuesta

0

No encontré otra forma viable de resolver este problema que utilizar un "índice de sobrecarga" en las clases generadas. Por lo tanto, el paquete

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; 

producirán estas clases:

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

Otras ideas se acaba de causar nuevos conflictos en el momento de generación de código, o en tiempo de ejecución.

ACTUALIZACIÓN: Nota, esta solución parece también el único para manejar situaciones como ésta correctamente:

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; 

Por lo que parece, este tipo de sobrecarga es posible en PL/SQL, también.

3

Su getReturnValue función podría determinar en tiempo de llamada que la función sobrecargada llamar dependiendo del número de parámetros de entrada se han establecido -, pero creo que va a llegar a ser más fácil si usted se pega a algo así como setParam1 en lugar de setName

+0

El método 'execute()' realiza la llamada real. El método se llama 'setName()' debido al argumento de la función 'name'. Lo arreglé en el ejemplo, para hacerlo más claro. Tu idea no es mala. Aunque, el problema es si tiene una sobrecarga de nombre de función con conjuntos de argumentos muy distintos, entonces puede ser confuso descubrir qué combinación de argumentos es posible. ¡Pero con los métodos de conveniencia, eso realmente podría funcionar! +1 para la idea de determinar la llamada correcta en tiempo de ejecución –

+0

@Lukas coincidir en tipos de argumento en lugar de nombres fue lo que quise decir con mi sugerencia, pensé que podría ser más simple. Creo que cualquiera de los dos sería posible en principio. –

+0

Es fácil encontrar una buena implementación sobre cómo llamar a la función en función de los nombres/tipos/posición de los argumentos. Pero la parte difícil es hacer que el código generado sea fácil de usar para los desarrolladores. Es por eso que uso el nombre del argumento en los métodos generados –

0

Puede superar las limitaciones de sobrecarga dando nombres únicos para cada función.Esto también mejoraría la legibilidad del código (esa es una de las razones why Golang doesn't have overloading). Por ejemplo, f_author_name_exists, f_author_name_country_exists.

Otra forma, que complicará las clases de Java, es decidir en tiempo de ejecución qué procedimiento llamar, en función de qué constructor de Java sobrecargado se usó o qué setters se usaron.

+0

Gracias por sus consejos. Como se indica en la pregunta, se trata de [jOOQ] (http://www.jooq.org), una utilidad que genera código fuente para los procedimientos almacenados, por lo que no tengo control sobre la sobrecarga del nombre del procedimiento, lo que no hago. mente en absoluto. Se agrega a la expresividad de una API al crear métodos de conveniencia. Por otro lado, debido a la presencia de parámetros 'OUT', es difícil decidir qué procedimiento llamar en el tiempo de ejecución, si esa llamada no está cableada en el momento de generación de código ... –

Cuestiones relacionadas