0

特定の日数を超えて存在したテーブルから行を削除しようとしています。行の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: org.hibernate.ejb.AbstractQueryImpl.registerParameterBinding(AbstractQueryImpl.java:360) の org.hibernate.ejb.QueryImpl で、パラメーター値 [604800000] がタイプ [java.lang.Double] と一致しませんでしたorg.hibernate.ejb.QueryImpl.setParameter(QueryImpl.java:72) の .setParameter(QueryImpl.java:364)

私は何を間違っていますか?

4

3 に答える 3

1

答えは非常に簡単です。

String template = "DELETE FROM %s WHERE current_timestamp() - start > :interval"; このクエリを作成する Hibernate は、この間隔値が Double 型であると想定します。

したがって、これを行うと問題が解決します。

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

必要に応じて、Java が long から double に変換できることを期待しています。しかし、long 値はボックス化されているため、Hibernate は単純にLong を Double にキャストしようとしますが、これは決して実りのないものです。

したがって、最初に double に変換すると、Double にボックス化され、Double は明らかに Double にキャスト可能になります。

では、ダブルはどこから来るのでしょうか?

SqlDate と Date 型の実装を確認しましたが、どちらも日付にマップされ、長い値との間で変換できます。また、タイムスタンプは日付にマップされます。

だから私はこれを試しました:

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 値であると予想されるため、interval は double であると予想されます。そしてそれが、Hibernateが不平を言っている理由です。

少し奇妙ですが、それがその通りであり、それが何が起こっているかの正確な説明です.

于 2013-10-01T22:10:32.957 に答える
0

HSQLをチェックしてください。問題は currentTimestamp と start に関連している可能性があります。HSQL キーワードまたは有効なプロパティであるとは考えられません。

名前のないパラメーターを使用して、そのインデックスを使用してパラメーターを設定しようとしましたか?

更新

設定が正しくないようです。String で算術計算を行いたい (開始)。

私は最近似たようなことをしました。時間を設定したタスクがあり、その後、タスクがタイムアウトしたかどうかを確認します(完了していませんが、タイムスタンプは以前よりも小さくなっています)。

ここにいくつかのコードがあります:

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 を使用していますが、簡単に変更してリストを取得できることにも注意してください。

于 2013-09-30T17:13:38.680 に答える