Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do in-query in jDBI?

Tags:

java

sql

jdbi

How can I execute somethings like this in jDBI ?

@SqlQuery("select id from foo where name in <list of names here>")
List<Integer> getIds(@Bind("nameList") List<String> nameList);

Table: foo(id int,name varchar)

Similar to @SelectProvider from myBatis.

Similar questions has been asked How do I create a Dynamic Sql Query at runtime using JDBI's Sql Object API?, but somehow answer is not clear to me.

like image 282
Mohit Verma Avatar asked Oct 17 '13 10:10

Mohit Verma


People also ask

Is JDBI an ORM?

Jdbi is not an ORM.

What is JDBI in Java?

JDBI is a SQL convenience library for Java. It attempts to expose relational database access in idiomatic Java, using collections, beans, and so on, while maintaining the same level of detail as JDBC. It exposes two different style APIs, a fluent style and a sql object style.

What is BindBean?

The @BindBean annotation binds JavaBeans™ properties by name. If no value is given to the annotation the bean properties will be bound directly to their property names. If a value is given, the properties will be prefixed by the value given and a period.


3 Answers

This should work:

@SqlQuery("select id from foo where name in (<nameList>)") List<Integer> getIds(@BindIn("nameList") List<String> nameList); 

Don't forget to annotate class containing this method with:

@UseStringTemplate3StatementLocator 

annotation (beacuse under the hood JDBI uses Apache StringTemplate to do such substitutions). Also note that with this annotation, you cannot use '<' character in your SQL queries without escaping (beacause it is a special symbol used by StringTemplate).

like image 105
Deinlandel Avatar answered Sep 20 '22 12:09

Deinlandel


Use @Define annotation to build dynamic queries in jDBI. Example:

@SqlUpdate("insert into <table> (id, name) values (:id, :name)") public void insert(@Define("table") String table, @BindBean Something s);  @SqlQuery("select id, name from <table> where id = :id") public Something findById(@Define("table") String table, @Bind("id") Long id); 
like image 45
Raven Avatar answered Sep 20 '22 12:09

Raven


With PostgreSQL, I was able to use the ANY comparison and bind the collection to an array to achieve this.

public interface Foo {
    @SqlQuery("SELECT id FROM foo WHERE name = ANY (:nameList)")
    List<Integer> getIds(@BindStringList("nameList") List<String> nameList);
}

@BindingAnnotation(BindStringList.BindFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface BindStringList {
    String value() default "it";

    class BindFactory implements BinderFactory {
        @Override
        public Binder build(Annotation annotation) {
            return new Binder<BindStringList, Collection<String>>() {
                @Override
                public void bind(SQLStatement<?> q, BindStringList bind, Collection<String> arg) {
                    try {
                        Array array = q.getContext().getConnection().createArrayOf("varchar", arg.toArray());
                        q.bindBySqlType(bind.value(), array, Types.ARRAY);
                    } catch (SQLException e) {
                        // handle error
                    }
                }
            };
        }
    }
}

NB: ANY is not part of the ANSI SQL standard, so this creates a hard dependency on PostgreSQL.

like image 29
Thomas Van Doren Avatar answered Sep 19 '22 12:09

Thomas Van Doren