JPA - 参数值[604800000]不匹配类型[java.lang.Double]

时间:2013-09-30 16:24:49

标签: java hibernate postgresql jpa

我尝试从表中删除超过给定时间的行数。行的start是时间戳。

EntityManager em = ...
long interval = ... // long value read from a properties file

String template = "DELETE FROM %s WHERE current_timestamp() - start > :interval";
String jpql = String.format(template , MyClass.class.getCanonicalName());

Query q = em.createQuery(jpql);
q.setParameter("interval", TimeUnit.DAYS.toMillis(interval));
q.executeUpdate();

MyClass.java

@Entity
@Table(name = "ROWS")
public class MyClass implements Serializable {

    private static final long serialVersionUID = 6070604872038740340L;

    puyblic MyClass() {
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "start", columnDefinition="TIMESTAMP WITH TIME ZONE")
    @Temporal(TemporalType.TIMESTAMP)
    private Date start;

    // getters ans setters...
}

但是,我得到以下例外:

  

引起:java.lang.IllegalArgumentException:参数值[604800000]不匹配类型[java.lang.Double]       在org.hibernate.ejb.AbstractQueryImpl.registerParameterBinding(AbstractQueryImpl.java:360)       在org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:364)       在org.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:72)

我做错了什么?

3 个答案:

答案 0 :(得分:2)

这是我如何解决我的问题:

我没有在JPQL中进行计算和比较,而是在Java代码中进行所有计算。最后的比较留给了JPQL。

String template = "DELETE FROM %s WHERE start < :calculatedStop";
String jpql = String.format(template , MyClass.class.getCanonicalName());

long calculatedStop = new java.util.Date().getTime() - INTERVAL;// INTERVAL is a constant

Query q = em.createQuery(jpql);
q.setParameter("calculatedStop", calculatedStop);
q.executeUpdate();

答案 1 :(得分:1)

答案很简单。

String template = "DELETE FROM %s WHERE current_timestamp() - start > :interval"; 构建此查询Hibernate期望此间隔值为Double类型。

这样做可以解决您的问题:

q.setParameter("interval", (double)TimeUnit.DAYS.toMillis(interval));

如果需要,我们都希望Java能够从long转换为double。但是由于长值是盒装的,Hibernate只是试图强制转换 Long to Double,这实际上并不富有成效。

因此,如果您将其转换为double,则将其设置为Double,Double显然可以转换为Double。

那么Double来自哪里?

我检查了SqlDate和Date类型的实现,并且都映射到日期,并且能够转换为long值和long值。时间戳也映射到日期。

所以我尝试了这个:

String template = "DELETE FROM %s WHERE current_timestamp() > :interval"; 它失败了,因为Hibernate抱怨Long与java.util.Date不兼容。因此,仅使用current_timestamp()映射到Date值。

对此也是如此:

String template = "DELETE FROM %s WHERE start > :interval";

当一个人试图从另一个日期减去一个日期时,双重发挥作用。所以使用任何: String template = "DELETE FROM %s WHERE current_timestamp() - current_timestamp() > :interval"; 要么 String template = "DELETE FROM %s WHERE start - start > :interval";

由于Date - Date的结果预计为Double值,因此

间隔预计为双倍。这就是Hibernate抱怨的原因。

有点奇怪,但这就是它的方式,这是对正在发生的事情的确切解释。

答案 2 :(得分:0)

请查看HSQL。问题可能与currentTimestamp和start有关。我想不出它是HSQL关键字或有效属性。

您是否尝试使用未命名的参数并使用其索引设置参数?

<强>更新

您的设置似乎不正确。您希望使用String(start)进行算术运算。

我最近做了类似的事情。我只有一个任务,我设置时间和之后,我检查任务是否超时(没有完成,但时间戳比之前更小)。

以下是一些代码:

1 /制图

long timestamp = 0; //default is 0

2 /设置时间戳

task.setTimestamp(System.currentTimeMillis()); session.getTransaction().commit()

3 /查询超时方法

   session.beginTransaction();
   long currentTime = System.currentTimeMillis();
   Criteria criteria = session.createCriteria(Task.class);
   criteria.add(Restrictions.eq("done", false));
   criteria.add(Restrictions.le("timestamp", currentTime - Task.TASK_TIMEOUT));
   Task task = (Task)criteria.uniqueResult();
   if(task != null) {
        task.setTimestamp(currentTime);
   }
   session.getTransaction().commit();

你可以看到我只是在这里使用标准搜索,因为它更简单。另请注意,我使用uniqueResult但您可以轻松更改它以检索列表。