2

我想调用一个存储过程(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
    }

谢谢你的任何想法。

4

3 回答 3

1

我认为它可以帮助您在没有 instanceof 的情况下实现所需的功能:http ://en.wikipedia.org/wiki/Visitor_pattern

于 2012-06-21T14:20:56.010 回答
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
  }
}
于 2012-06-21T14:46:30.323 回答
1

我将实施另一种解决方案,这可能不是最好的解决方案,但在我看来,虽然不臭。

作为StoredProcedure一个接口,每个存储过程都实现了这个接口。因此,每个实现都将包含一个返回call ...语句的方法,因为开发人员知道他实现的过程所需的参数类型。

于 2012-06-21T15:24:25.450 回答