2015-02-06 59 views
1

我正在使用JDBI和Dropwizard,並且遇到流暢查詢的問題。我有一個API端點,看起來像這樣:JDBI Fluent查詢問題

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個查詢中的哪一個。如果我要添加另一個查找參數(例如accountId),這意味着我現在需要有6個查詢(每個可能性1個)和6個if語句來確定要運行哪個查詢。

有沒有簡單的方法來解決這個與JDBI?我已經研究過@Define的可能性,但這會帶來SQL注入的風險。電子郵件和暱稱都是字符串。

我理想只需要一個查詢:

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

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

如果暱稱爲null,將忽略暱稱要求,只是詢問過的電子郵件。是這樣的可能嗎?

編輯/ 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 DAO使用@define:

我現在爲了清理我的代碼有點做到了這一點。通過這樣做,我可以削減我的6個查詢(每個案例1個查詢,因爲有3個查詢字段),以及6個查詢語句減少到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

我們可以在單一的查詢,而不是在Java代碼構建SQL也做到這一點。雖然有點不好意思。

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

好主意,但在技術上你應該使用(合併(:電子郵件, '')= '' OR =電子郵件:電子郵件)來匹配bcam909的if(Strings.isNullOrEmpty(電子郵件)!)。與暱稱相同。 – alecswan 2015-02-06 18:50:24

+0

如果電子郵件地址和暱稱都不爲空,這將會起作用。如果暱稱和電子郵件都爲空,它將返回所有帳戶。在調用此查詢之前,我必須添加一個支票,以確保暱稱和電子郵件都不爲空或空。 – bcam909 2015-02-06 22:28:20