web-dev-qa-db-ja.com

入力パラメーターを持つ名前付きクエリ

私はHibernateでJPAを学び、Mavenも使用しています。私の問題は、名前付きクエリのUPDATEおよびSET句で入力パラメーターを使用するにはどうすればよいですか?

 @NamedQuery(name = "updateEmailAddress", query = "Update User u set u.email = :email where u.username = :username")

パラメータがWHEREまたはHAVING句でのみ使用できるというエラーが表示されます。いくつかの記事を参照しましたが、適切な解決策が見つかりません。

JPA 2.0以下では、名前付きクエリのset句でパラメーターを使用できません。リテラルのみ。 JPA 2.1を使用している場合、この制限は解除されます。

私が収集できるものから、あなたはJPA 2.1を使用していません。したがって、この制限を回避する方法をいくつか紹介します。

オプション1:createQueryメソッドを使用して、動的に生成された文字列をメソッドに渡します。

    String queryString = generateQueryString(email, username);
    entityManager.createQuery(queryString).executeUpdate();

オプション2:関連するエンティティを更新してマージします。

    List<User> result = entityManager.createQuery('select u from user u where 
    u.username = :username').setParameter('username', username).getResultList(); 
    for (User user : result) {
        user.setEmail(email);
        entityManager.merge(user);
    }

オプション3:JPQLではなくHQLを使用してクエリを作成します。あなたはエンティティマネージャーの後ろを向いているので、私はこれをテストしていませんし、お勧めしません。

    Query q = sessionFactory.getCurrentSession().createNamedQuery('updateEmailAddress');
    q.setParameter('email', email);
    q.setParameter('username', username);
    q.executeUpdate();
9
Xavier Hammond

実際にはJPA 2.1まではこれが許可されていませんでしたが、プロバイダーはそのようにパラメーターを提供できるため、実際に使用できます(これは良いことです)。

JPAプロバイダーはこの検証に関する仕様に準拠していないようですが、それは意味がないためだと思います(2.1で確認できるようになりました)。 「なぜ開発者を難しくするのですか?」

私はEclipseLink 2.3.1も使用していますが、問題なく動作しています。

推奨される解決策

EclipseのJPQLクエリ検証を無効にするだけです。

プロバイダーがそれを受け入れる場合は問題ありません。そうでない場合は、仕様に準拠する必要があります。とても簡単です。コードはよりクリーンになり、仕様の最近の評価に準拠します。

ちょうど行く:Preferences > Java Persistence > JPA > Errors/Warnings > Queries and Generators > Invalid or incomplete JPQL queries:およびIgnoreそれ

詳細は この記事 を確認してください:

結論

Hibernateはこの点で仕様に準拠していませんが、新しいバージョンのJPA-specでは、ドラフトJSRで示されているように、この動作が許可されていると推測できます。 JBoss Toolsはおそらく仕様に基づくJPQL-grammarに対してクエリを検証しているため、検証エラーが表示されています。

そしてこれが解決策です:

最後のコメント

外のチームで話し合った後、仕様に違反しても現在の実装を維持することにしました。動作を変更することは、クエリを構築するための文字列連結または文字列置換を意味し、現在のアプローチははるかにクリーンです。この段階で永続性プロバイダーまたはアプリケーションサーバーの変化の兆候は見られないので、コードを維持することによる利益は、現時点でのリスクよりも大きいと考えています。

1
Evandro Pomatti

次のような名前のクエリを作成する必要があります。

Query query = getEntityManager().createNamedQuery("updateEmailAddress");

query.setParameter("email", "[email protected]");
query.setParameter("username", "emailuser");

int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

出典:

0
Carlos Laspina

位置パラメータを試して、それが機能するかどうかを確認できますか?

@NamedQuery(name = "updateEmailAddress", query = "UPDATE User u SET u.email = ?1 WHERE u.username = ?2")

//The parameter needs to be passed as
query.setParameter(1, "the_emailaddress");
query.setParameter(2, "the_username");
0
zapping