2015-02-06 2 views
1

Я использую JDBI с Dropwizard, и у меня проблема с быстрыми запросами. У меня есть апи конечную точку, которая выглядит следующим образом:JDBI Fluent Query Issue

public Response getAccount(@QueryParam("nickname") String nickname, @QueryParam("email") String email); 

Я пытаюсь должны избегать написания следующих 3 запросов:

@SqlQuery( " SELECT * FROM ACCOUNT WHERE EMAIL = :email " ) 

public Account getAccountByEmail(@Bind("email") String email); 


@SqlQuery(" SELECT * FROM ACCOUNT WHERE NICKNAME = :nickname ") 

public Account getAccountByNickname(@Bind("nickname") String nickname); 


@SqlQuery(" SELECT * FROM ACCOUNT WHERE NICKNAME = :nickname AND EMAIL = :email " ) 

public Account getAccount(@Bind("nickname") String nickname, @Bind("email") String email); 

Это также означает, что моя реализация для метода getAccount имеет 3 если проверяет ... ник и нет электронной почты, электронной почты и никнейма, электронной почты и псевдонима, чтобы определить, какой из 3 запросов для запуска. Если бы я добавил еще один параметр lookup (например, accountId), это означало, что теперь мне нужно иметь 6 запросов (по 1 для каждой возможности) и 6 операторов if для определения того, какой запрос запускать.

Есть ли простой способ обойти это с помощью JDBI? Я рассмотрел возможность @Define, однако это представляет риск SQL-инъекции. Email и Nickname - это строки.

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

@SqlQuery(" SELECT * FROM ACCOUNT WHERE NICKNAME = :nickname AND EMAIL = :email " ) 

public Account getAccount(@Bind("nickname") String nickname, @Bind("email") String email); 

Если ник был нулевым это игнорировать бы требование ника и просто запросить от электронной почты. Что-то вроде этого возможно?

EDIT/UPDATE:

Я теперь сделал это для того, чтобы очистить мой код немного:

@SqlQuery(" SELECT * FROM ACCOUNT WHERE <query> ") 
    public Account getAccount(@Bind("id") Long id, @Bind("nickname") String nickname, @Bind("email") String email, @Define("query") String query); 

Я обновил свой JDBI дао использовать @Define. Делая это, я могу сократить 6 запросов (1 запрос для каждого случая, так как есть 3 поля запроса) и 6 операторов if до 1 запроса и 3 оператора if.

Account account = null; 
    StringBuilder query = new StringBuilder(); 

    if(accountId != null) { 
     query.append(" ID = :id "); 
    } 
    if(!Strings.isNullOrEmpty(nickname)) { 
     if(query.length() > 0) query.append(" AND "); 
     query.append(" NICKNAME = :nickname "); 
    } 
    else if(!Strings.isNullOrEmpty(email)) { 
     if(query.length() > 0) query.append(" AND "); 
     query.append(" EMAIL = :email "); 
    } 

    account = accountDAO.getAccount(accountId, nickname, email, query.toString()); 

Я бы предпочел не использовать определение, хотя хотел бы сохранить логику запросов в DAO. Было бы хорошо, если бы что-то подобное было вообще возможно:

SELECT * FROM ACCOUNT WHERE @IfNotNull(id = :id) 
AND @IfNotNull(email = :email) AND @IfNotNull(nickname = :nickname) 

ответ

1

Мы можем добиться этого и в одном запросе вместо построения SQL в Java коде. Хотя немного взломать.

select * from account where 
(COALESCE(:email, NULL) IS NULL OR email = :email) and 
(COALESCE(:nickname, NULL) IS NULL OR nickname = :nickname) ; 
+0

Хорошая идея, но технически вы должны использовать (коалесценции (: электронная почта, '') = '' или по электронной почте =: электронная почта), чтобы соответствовать bcam909, если (Strings.isNullOrEmpty (электронная почта)!). То же самое с псевдонимом. – alecswan

+0

Это будет работать, если оба адреса электронной почты и псевдоним не равны нулю. Если оба псевдонима и адрес электронной почты были пустыми, он будет возвращать все учетные записи. Я должен был бы добавить проверку перед вызовом этого запроса, чтобы удостовериться, что псевдоним и электронная почта были не пустыми или пустыми. – bcam909