【问题标题】:JDBI Fluent Query IssueJDBI Fluent 查询问题
【发布时间】:2015-02-06 18:00:20
【问题描述】:

我将 JDBI 与 Dropwizard 结合使用,但遇到了流畅查询的问题。我有一个如下所示的 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 注入的风险。电子邮件和昵称都是字符串。

理想情况下,我只需要一个查询:

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

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

如果昵称为空,它将忽略昵称要求并仅查询电子邮件。这样的事情可能吗?

编辑/更新:

我现在这样做是为了稍微清理一下我的代码:

    @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 个 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)

【问题讨论】:

    标签: sql dropwizard jdbi


    【解决方案1】:

    我们也可以在单个查询中实现这一点,而不是在 java 代码中构造 sql。不过有点hacky。

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

    【讨论】:

    • 好主意,但从技术上讲,您应该使用 (coalesce(:email, '') = '' OR email = :email) 来匹配 bcam909 的 if(!Strings.isNullOrEmpty(email))。与昵称相同。
    • 如果电子邮件和昵称都不为空,这将起作用。如果昵称和电子邮件都为空,它将返回所有帐户。我必须在调用此查询之前添加一个检查,以确保昵称和电子邮件都不为空或为空。
    猜你喜欢
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 2010-10-29
    • 1970-01-01
    • 1970-01-01
    • 2013-05-27
    相关资源
    最近更新 更多