如何将IN运算符与JDBI结合使用?

时间:2017-10-27 13:32:05

标签: java oracle11g jdbi

下午好。

我正在尝试将带有字符串的列表绑定到IN运算符使用的查询。 我正在使用Oracle。 我按照链接描述的示例进行了操作: How to use IN operator with JDBI?

<input type="text" placeholder="From" class="week" id="dt1">
<input type="text" placeholder="To" disabled="disabled" class="week" id="dt2">

$(function() {
  $("#dt1").datepicker({
    minDate: "-",
    maxViewMode: "weeks",
    format: "dd-mm-yy",
    clearBtn: true,
  }).on('changeDate', function(event) {
    $('#dt2').removeAttr('disabled'); //We enable our #To Picker
    var newDate = new Date(event.date);
    newDate.setDate(newDate.getDate() + 6); //We add 6 days to our selected date
    $("#dt2").datepicker("setStartDate", event.date); //Set as start point that selected day 
    $("#dt2").datepicker("setEndDate", newDate); //Set the final "MaxDate

  });
   //We do the same for this one but backwards to avoid puttin "invalid" dates
  $("#dt2").datepicker({
    minDate: 0,
    format: 'dd-mm-yyyy',
    endDate: "today"
  }).on('changeDate', function(event) {
    var newDate = new Date(event.date);
    newDate.setDate(newDate.getDate() - 6);

    //You can alway remove this line to allow your user to select any start date
    $("#dt1").datepicker("setStartDate", newDate);
    //And here we set our max date on From picker so he doesn't again enter "invalid" dates
    $("#dt1").datepicker("setEndDate", event.date);

  });
});

我创建了一个ListArgumentFactory

List<String> ms = new ArrayList();
    ms.add("Novosibirsk");
    ms.add("Perm");

public interface CityDAO {
   @RegisterMapper(CitiesMapper.class)
   @SqlQuery("SELECT *
              FROM Universities
              WHERE Location IN (:cities)")
   List<cities> getItems(@Bind("cities") List<String> cities);}
 }

我注册了工厂

public class ListArgumentFactory implements ArgumentFactory<List> {
    @Override
    public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
    return value instanceof List;
    }

   @Override
   public Argument build(Class<?> expectedType, final List value, StatementContext ctx) {
    return new Argument() {
        @Override
        public void apply(int position, PreparedStatement statement, StatementContext ctx) throws SQLException {
            String type = null;
            if(value.get(0).getClass() == String.class){
                type = "varchar";
            } else if(value.get(0).getClass() == Integer.class){
                // For integer and so on...
            } else {
                // throw error.. type not handled
            }
            Array array = ctx.getConnection().createArrayOf(type, value.toArray());
            statement.setArray(position, array);
        }
    };
  }
 }

但是当我提出请求时,我得到了一个异常

   public class DBI extends AbstractModule {
     private DBI dbi;

     @Override
     protected void configure() {
       this.dbi = new DBI(provideConfig().url());
       this.dbi.registerArgumentFactory(new ListArgumentFactory());
    }
  }

帮我弄清楚我做错了什么

1 个答案:

答案 0 :(得分:0)

根据JDBI documentation,使用Oracle实现类似的功能可能非常复杂,因此使用所描述的第一种方法(UseStringTemplate3StatementLocator)可能更好:

  

Oracle支持类似的东西,但您需要使用Oracle特定的API和oracle.sql.ARRAY实例。在Oracle的情况下,您必须首先在数据库中预先声明数组类型,并在将数组存储在数据库中时,在调用后将其释放。

话虽如此,有一种简单的方法可以用来在Oracle中完成这项工作,即用逗号连接列表中的元素。我使用Java 8 String.join方法修改了ListArgumentFactory:

public class ListArgumentFactory implements ArgumentFactory<List> {

    @Override
    public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
        return value instanceof List;
    }

    @Override
    public Argument build(Class<?> expectedType, final List value, StatementContext ctx) {
        return new Argument() {
            @Override
            public void apply(int position, PreparedStatement statement, StatementContext ctx) throws SQLException {
                statement.setString(position, String.join(",", value));
            }
        };
    }
}

我已经尝试过JDBI文档中描述的方法,在Oracle DB中使用oracle.sql.ARRAY和自定义TYPE,但对我来说并不成功。