我想调用存储过程(Oracle)。因为我的过程调用是动态的,我需要动态管理过程参数。
问题是我想避免使用instanceof
关键字,因为它不适用于主要类型。
是否有更简洁的方法来调用此类程序?
public void executeProcedure(StoredProcedure proc) {
LinkedList<ProcedureParameter<?>> parameters = proc.getParameters();
CallableStatement statement = connection.prepareCall("{ call MY_PACKAGE.MY_PROCEDURE( ?, ?, ? ) }");
for (int i = 0; i < parameters.size(); i++) {
Object paramValue = parameters.get(i).getValue();
// Beginning of smelly code
if (paramValue instanceof String) {
statement.setString(i + 1, (String) paramValue);
}
else if (paramValue instanceof ...) {
...
}
else {
...
}
// End of smelly code
}
statement.execute();
}
public class ProcedureParameter<E> {
private String name;
private E value;
public ProcedureParameter(String name) {
this.name = name;
}
public ProcedureParameter(String name, E value) {
this.name = name;
this.value = value;
}
// Getters and setters
}
谢谢你的任何想法。
答案 0 :(得分:1)
我认为它可以帮助您在没有instanceof http://en.wikipedia.org/wiki/Visitor_pattern
的情况下实现所需的功能答案 1 :(得分:1)
你可以使用反射,虽然这不是好习惯,因为它较慢并且阻止编译器检查以确保方法调用是正确的。您可以将每个类映射到其对应的CallableStatement
方法。例如,String
将映射到“setString”。
List<ProcedureParameter<?>> parameters = proc.getParameters();
CallableStatement statement = connection.prepareCall("{ call MY_PACKAGE.MY_PROCEDURE( ?, ?, ? ) }");
Map<Class<?>, String> methods = new HashMap<Class<?>, String>();
methods.put(String.class, "setString");
//...
for (int i = 0; i < parameters.size(); i++) {
Object paramValue = parameters.get(i).getValue();
Class<?> paramValueClass = paramValue.getClass();
String stmtMethod = methods.get(paramValueClass);
if (stmtMethod != null){
Method method = statement.getClass().getMethod(stmtMethod, int.class, paramValueClass);
method.invoke(statement, i+1, paramValue);
} else {
//error
}
}
答案 2 :(得分:1)
我会实施另一个解决方案,这可能不是最好的解决方案,但在我看来,不是很臭。
由于StoredProcedure
是一个接口,每个存储过程都实现此接口。因此,每个实现都将包含一个返回call ...
语句的方法,因为开发人员知道他实现的过程所需的参数类型。