2010-12-14 3 views
6

В моей библиотеке сопряжения базы данных jOOQ, я хотел бы добавить поддержку пакетов Oracle (или DB2 и т. Д.). Я уже реализовал поддержку хранимых процедур/функций, где каждый сохраненный объект моделируется как сгенерированный Java-класс. Например, эта хранимая функцияСопоставление между пакетами Oracle и пакетами Java

CREATE FUNCTION f_author_exists (author_name VARCHAR2) RETURNS NUMBER; 

будет создать класс, который может быть использован как (обратите внимание, есть также множество удобных методов, этот пример как раз показывает общий дизайн):

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

Причина, по которой я выбрал сопоставление SQL-функция ->Java-класс объясняется тем, что хранимые процедуры позволяют получить комплексные возвращаемые значения (несколько параметров OUT или IN OUT), которые я хочу получить один за другим после вызова процедуры:

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

Теперь эта конструкция отлично работает с сохраненными функций/процедур, где перегрузки не представляется возможным. В пакеты Oracle (или в DB2), однако, я могу иметь несколько функций с тем же именем, как и

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; 

Когда я создать класс за функции (или процедуры), у меня будет именования столкновения с несколькими FAuthorExists классов Java , Хлопочным решением является добавление индекса к имени класса, например FAuthorExists2, FAuthorExists3. Другим хромым решением является генерация какого-либо хэш-значения (или самого значения) из имен/типов параметров непосредственно в имя класса, например FAuthorExistsVARCHAR2, FAuthorExistsVARCHAR2VARCHAR2. По очевидным причинам ни одно из решений не желательно.

У кого-нибудь есть простое решение этой проблемы? Или, может быть, идея лучшего общего дизайна, которая не вызывала бы такие проблемы с перегрузкой имени функции?

Любая оценка приветствуется!

ответ

0

Я не нашел другого жизнеспособного способа решения этой проблемы, кроме использования «индекса перегрузки» для сгенерированных классов. Таким образом, пакет

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; 

будет производить эти классы:

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

Другие идеи просто вызвать новые конфликты во время генерации кода, или во время выполнения.

UPDATE: Обратите внимание, это решение также кажется, единственный, чтобы справиться с ситуациями, как этот правильно:

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; 

Как мне кажется, этот вид перегрузки можно в PL/SQL, тоже.

3

Ваша функция getReturnValue может определить во время вызова, который перегруженной функции для вызова в зависимости от того, сколько входные параметры были установлены, - но я думаю, что это будет в конечном итоге проще, если вы будете придерживаться что-то вроде setParam1, а не setName

+0

Метод 'execute()' выполняет фактический вызов. Метод называется 'setName()' из-за аргумента функции 'name'. Я исправил это в примере, чтобы сделать его более понятным. Ваша идея не плохая. Хотя проблема состоит в том, что если вы перегружаете имя функции с помощью очень разных наборов аргументов, тогда может возникнуть путаница выяснить, какая комбинация аргументов возможна. Но с помощью удобных методов это может сработать! +1 для идеи определения правильного вызова во время выполнения –

+0

Соответствие @Lukas по типам аргументов, а не имен, было тем, что я имел в виду под моим предложением - я думал, что это может быть проще. Я думаю, что в принципе возможно. – 2010-12-14 15:48:32

+0

Легко найти хорошую реализацию о том, как вызвать функцию, основанную на именах/типах аргументов. Но сложная задача - сделать сгенерированный код простым в использовании для разработчиков. Вот почему я использую имя аргумента в сгенерированных методах –

0

Вы можете преодолеть ограничения перегрузки, указав уникальные имена для каждой функции.Это также улучшит читаемость кода (это одна из причин why Golang doesn't have overloading). Например, f_author_name_exists, f_author_name_country_exists.

Другой способ, который усложнит классы Java, заключается в том, чтобы решить во время выполнения, какую процедуру вызывать, на основе которой использовался перегруженный конструктор Java или какие сеттеры были использованы.

+0

Спасибо за ваши подсказки. Как указано в вопросе, речь идет о [jOOQ] (http://www.jooq.org), утилите, которая генерирует исходный код для хранимых процедур, поэтому у меня нет контроля над перегрузкой имени процедуры, Разум. Это добавляет к выразительности API при создании удобных методов. С другой стороны, из-за наличия параметров «OUT» трудно решить, какую процедуру вызывать во время выполнения, если этот вызов не является жестким во время генерации кода ... –

Смежные вопросы