【问题标题】:Hibernate query building based on conditions基于条件的休眠查询构建
【发布时间】:2011-11-18 07:30:40
【问题描述】:

我有一个表单,用户可以在其中选择搜索条件。

标准是:

Product Name: Input field
Name Option: Radio button group - begins with (default selected)/ is/ contains
Country: dropdown of country
Status: All, Active, Blocked
Type: All, One, Two, Three

只有产品名称是强制性的。其他下拉菜单是可选的。

所以如果没有给出国家,我应该找到所有国家的产品。 如果没有给出 active,我应该找到 active 和 block 的产品。 如果没有给出类型,我应该返回所有三种类型的产品。

我正在构建休眠查询如下:

String productName = searchCriteria.getValue("productName");
String productNameCriteria = searchCriteria.getValue("productNameCriteria");
String country = searchCriteria.getValue("country");
String status = searchCriteria.getValue("status");
String type = searchCriteria.getValue("type");

Query prodQuery = null;
String prodSql = "select count(*) from Product p where";

// is
if (productNameCriteria.equalsIgnoreCase("IS")){
            prodSql += "p.productName = '"+productName+"'";
        }

// begins with
else if (productNameCriteria.equalsIgnoreCase("BEGINS WITH")){
            prodSql += "p.productName = '"+productName+"%'";
        }

// contains
else (productNameCriteria.equalsIgnoreCase("BEGINS WITH")){
            prodSql += "p.productName = '%"+productName+"%'";

        }

if(!country.equalsIgnoreCase("0")){
         prodSql += " and p.country = '"+country+"'";
     }

if(!status.equalsIgnoreCase("ALL")){
      if(status.equalsIgnoreCase("active"))
          prodSql += " and p.status = 'active'";

      else
          prodSql += " and p.status = 'blocked'";
 }

 if(!type.equalsIgnoreCase("ALL")){
      if(type.equalsIgnoreCase("one"))
          prodSql += " and p.type = 'one'";

      else if(type.equalsIgnoreCase("two"))
          prodSql += " and p.type = 'two'";

      else 
         prodSql += " and p.type = 'three'";
}

prodQuery = this.em.createQuery(prodSql);
List<Object[]> results = prodQuery.getResultList();

我是否以正确的方式进行查询构建?或者有没有其他有效的方法???

感谢阅读!!

【问题讨论】:

标签: java hibernate jpa orm


【解决方案1】:

试试看Criteria Query

Criteria crit = sess.createCriteria(Product.class);
if (productNameCriteria.equalsIgnoreCase("IS"))
    crit.add( Restrictions.eq("productName", productName);
else if (productNameCriteria.equalsIgnoreCase("BEGINS WITH"))
    crit.add( Restrictions.like("productName", productName + "%")
// etc

如果您绝对必须构建字符串查询,那么您应该使用StringBuilder

StringBuilder sb = new StringBuilder();
sb.append("select count(*) from Product p where ");
if (productNameCriteria.equalsIgnoreCase("IS"))
    sb.append("p.productName = '").append(productName).append("'");
// etc
String query = sb.toString();

使用StringBuilder 可减少运行时创建的实例数量。

您还可以考虑使用查询参数,这将降低一些查询复杂性,尽管我不知道运行时查询性能影响是什么。

"select count(*) from Product p where p.productName = :productName"
"select count(*) from Product p where p.productName = ?"

然后您可以使用Query#setParameter(或其他变体之一,如setString)来定义查询中的值。这也是构建查询的好得多的方法,因为它将自动管理您从 UI 接收到的值的引用和转义。 使用查询参数而不是字符串连接,无论您如何构建查询字符串。

【讨论】:

  • 抱歉.. 但由于我正在使用 websphere v6.1,因此无法使用较新版本的 JPA 我将不得不按照我在问题中解释的方式进行查询构建。我构建它的方式是否正确???/
【解决方案2】:

是的。如果您以这种方式动态构建查询,它将起作用。但是代码会变得乏味和嘈杂,因为它涉及到 where-condition 子句的字符串操作。

对于这种查询的用例,这是一种允许用户指定一系列不同属性值与返回结果集匹配的搜索,使用 Query By Example(QBE ) 更高效、更优雅。

QBE 的想法是,你提供一个被查询类的实例,并初始化一些属性,查询将返回具有匹配属性值的记录。


参考

【讨论】:

  • 感谢您的回复。但正如评论中提到的,我不能使用 Criteria Builder,因为我必须使用 websphere v6.1
猜你喜欢
  • 2018-07-25
  • 1970-01-01
  • 2011-06-08
  • 1970-01-01
  • 2011-04-13
  • 2017-03-21
相关资源
最近更新 更多