【问题标题】:optional parameters jpa 2.1可选参数 jpa 2.1
【发布时间】:2017-06-08 19:39:08
【问题描述】:

我有这门课,

@Entity
public class Message {

  @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
  private long id;

  @Column( nullable = false )
  private String mobile;

  @Column( nullable = false )
  private String message;

  @Column( nullable = false )
  private Lang lang;

  @Column( nullable = false )
  private int status;

  @Column( nullable = false )
  private Calendar creationDate;
  ...
}

我希望能够使用表单中的可选参数查询表。我正在使用 JPA 2.1 和休眠。有没有办法在没有多个查询语句或没有将我的应用程序与休眠或我正在使用的特定数据库紧密耦合的情况下做到这一点?

这是我使用的表格:

<form action="${pageContext.request.contextPath}/search">
<label>From</label>
<input type="datetime" placeholder="dd/mm/yy hh/mm" name="from" required> 
<label>To</label>
<input type="datetime" placeholder="dd/mm/yy hh/mm" name="to" required> 
<select name="lang">
    <option value="english">English</option>
    <option value="arabic">Arabic</option>
</select>
<input type="tel" placeholder="Recipient" name="recipient">
<select name="status">
    <option value="new">New</option>
    <option value="picked">Picked</option>
    <option value="sent">Sent</option>
    <option value="rejected">Rejected</option>
</select>
<input type="submit" value="Search">

更新::::::::::::::::::::::::::::

我试过了:

    public List<Message> getMessages(Calendar fromDate, Calendar toDate, String lang, String recipient, String status) {
    /*TypedQuery<Message> query = em.createQuery(
            "SELECT e FROM Message e WHERE e.creationDate BETWEEN :fromDate AND :toDate", Message.class);
    query.setParameter("fromDate", fromDate);
    query.setParameter("toDate", toDate);
    List<Message> list = query.getResultList();
    return list;*/

    List<Predicate> predicates = new ArrayList<>();

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Message> query = cb.createQuery(Message.class);
    Root<Message> root = query.from(Message.class);

    predicates.add(cb.between(root.get("creationDate"), fromDate, toDate));

    if (lang != null && !lang.equalsIgnoreCase("any")) {
           predicates.add(cb.equal(root.get("lang"), lang));
        }

    if (recipient != null && !recipient.equals("")) {
           predicates.add(cb.equal(root.get("mobile"), recipient));
        }

    if (status != null && !status.equalsIgnoreCase("any")) {
           predicates.add(cb.equal(root.get("mobile"), recipient));
        }

    query.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
    List<Message> list = em.createQuery(query).getResultList();

    return list;
}

但我收到以下错误:

java.lang.IllegalArgumentException: Parameter value [0] did not match expected type [entity.Lang (n/a)]
at org.hibernate.jpa.spi.BaseQueryImpl.validateBinding(BaseQueryImpl.java:897)
at org.hibernate.jpa.internal.QueryImpl.access$000(QueryImpl.java:61)
at org.hibernate.jpa.internal.QueryImpl$ParameterRegistrationImpl.bindValue(QueryImpl.java:235)
at org.hibernate.jpa.spi.BaseQueryImpl.setParameter(BaseQueryImpl.java:638)
at org.hibernate.jpa.spi.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:163)
at org.hibernate.jpa.spi.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:32)
at org.hibernate.jpa.criteria.compile.CriteriaCompiler$1$1.bind(CriteriaCompiler.java:109)
at org.hibernate.jpa.criteria.CriteriaQueryImpl$1.buildCompiledQuery(CriteriaQueryImpl.java:369)
at org.hibernate.jpa.criteria.compile.CriteriaCompiler.compile(CriteriaCompiler.java:130)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:699)
at dao.MessageDAO.getMessages(MessageDAO.java:63)

【问题讨论】:

  • 尝试使用 Lang.valueOf(lang) 所以你传递的是一个 Lang 对象,而不是它的字符串表示

标签: java jpql jpa-2.1


【解决方案1】:

简短的回答:是的。您无需使用特定于 hibernate 的类来构建满足您需求的查询。

但是,您可能希望在构建查询之前过滤掉可选参数。 如果telnull/empty,您可能不想在查询中包含它。所以不要将它添加到查询中。 查看the Java EE persistence tutorialCriteriaBuilder javadoc,按照您需要的方式构建您的TypedQuery

伪代码(显然未经测试......但我希望你明白):

List<Predicate> predicates = ...
CriteriaBuilder cb = ...
Root<?> table = ...
if (isNotBlank(tel)) {
   predicates.add(cb.equal(table.get("tel"), tel));
}
if (isNotBlank(...)) {
   predicates.add(cb.like(table.get("..."), ...));
}
...
query.where(cb.and(predicates.toArray(Predicate[]::new)));

也许还有以下帮助:Really dynamic JPA CriteriaBuilder

【讨论】:

  • 谢谢我现在正在尝试。
【解决方案2】:

这里有一个更好的方法来根据可选参数进行更新

public int updateMyEntity(String value1, String value2){

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaUpdate<MyEntity> cu = cb.createCriteriaUpdate(MyEntity.class);
    Root<MyEntity> root = cu.from(MyEntity.class);

    if (value1 != null) {
        cu.where(cb.equal(root.get(MyEntity.value1), value1));
    }

    if (value2 != null) {
        cu.where(cb.equal(root.get(MyEntity.value2), value2));
    }

    // set 
    cu.set(MyEntity_.isAvailable,  true);

    return em.createQuery(cu).executeUpdate();
}

【讨论】:

  • UPDATE 语句的好答案,但我认为 OP 要求的是 SELECT 查询。
  • 我知道,他问的是可选参数,所以我给了他一个例子:-)
猜你喜欢
  • 2013-06-02
  • 2023-03-11
  • 2017-11-29
  • 1970-01-01
  • 2018-08-16
  • 2014-10-30
  • 2019-04-22
  • 1970-01-01
  • 2018-03-18
相关资源
最近更新 更多