Dropwizard で JDBI を使用していますが、流暢なクエリに問題があります。次のようなAPIエンドポイントがあります。
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 つの if チェックがあることも意味します... ニックネームあり、電子メールなし、電子メールあり、ニックネームなし、電子メールあり、ニックネームで、3 つのクエリのどれを実行するかを決定します。別のルックアップ パラメーター (accountId など) を追加すると、実行するクエリを決定するために 6 つのクエリ (可能性ごとに 1 つ) と 6 つの if ステートメントが必要になります。
JDBIでこれを回避する簡単な方法はありますか? @Define の可能性を調べましたが、これには SQL インジェクションのリスクがあります。電子メールとニックネームはどちらも文字列です。
理想的には、クエリは 1 つだけ必要です。
@SqlQuery( " SELECT * FROM ACCOUNT WHERE NICKNAME = :nickname AND EMAIL = :email " )
public Account getAccount(@Bind("nickname") String nickname, @Bind("email") String email);
ニックネームが null の場合、ニックネームの要件は無視され、メールからクエリが送信されます。このようなことは可能ですか?
編集/更新:
コードを少しクリーンアップするために、これを実行しました。
@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);
@Define を使用するように JDBI ダオを更新しました。これにより、6 つのクエリ (クエリ フィールドが 3 つあるため、ケースごとに 1 つのクエリ) と、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に保持したいので、defineを使用する必要はありません。このようなことがまったく可能であれば、それは素晴らしいことです:
SELECT * FROM ACCOUNT WHERE @IfNotNull(id = :id)
AND @IfNotNull(email = :email) AND @IfNotNull(nickname = :nickname)