jpa 手动预编译_编译时检查JPA查询
jpa 手動預編譯
JPA提供了幾種查詢數據的方法。 可以根據各種標準(例如,使用的語言(SQL與JPQL)或查詢是靜態的(編譯時間)還是動態的(執行時間))對此類替代方案進行分類。
靜態查詢是使用@Entity類定義本身中的注釋@NamedQuery ( javax.persistence.NamedQuery )和@NamedQueries ( javax.persistence.NamedQueries )定義的:
另一方面, EntityManager提供了分別接受JPQL或SQL查詢的createQuery(…)和createNativeQuery(…)方法。
因此,可以在編譯或執行時定義查詢。
( 注意 :建議始終使用Query中的 setParameter(…)方法來使用參數化查詢,以避免SQL注入漏洞。)
標準API
但是,JPA提供了另一種查詢對象的方法: Criteria API 。 確實,切換到JPA的動機之一是處理對象而不是SQL方言,不是嗎?
讓我們看一個示例代碼。
實體定義:
@Entity public class User {@Idprivate Integer userId;@Basic@Column(length=15, nullable=false)private String name;@Basic@Column(length=64, nullable=false)private String userDigestedPasswd;@Basic@Column(length=50, nullable=true)private String email;@Basic@Column(nullable=false)public Integer privilegeLevel;@Basic@Column(nullable=false)private Boolean active; }讓我們查詢數據庫并檢查結果(使用JUnit):
public class UserTest {@Testpublic void testUserCriteria(){ EntityManagerFactory emf = null; EntityManager em = null; try {emf = Persistence.createEntityManagerFactory("criteria");em = emf.createEntityManager();final CriteriaBuilder cb = em.getCriteriaBuilder();final CriteriaQuery<User> q = cb.createQuery(User.class);final Root<User> users = q.from(User.class);final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);q.select(users).where(condition).orderBy(cb.asc(users.get("userId")));em.getTransaction().begin();List<User> result = em.createQuery(q).getResultList();em.getTransaction().commit();assertNotNull(result);assertEquals(2, result.size());assertEquals(1, (int)result.get(0).getUserId());assertEquals("Pepe", result.get(0).getName());assertEquals(3, (int)result.get(1).getUserId());assertEquals("Dolores", result.get(1).getName());} catch (Exception e) {fail("Unexpected Exception " + e.getMessage()); } finally {if (em != null)em.close();if (emf != null)emf.close(); } } }以下幾行顯示查詢的創建:
final CriteriaBuilder cb = em.getCriteriaBuilder();final CriteriaQuery<User> q = cb.createQuery(User.class);final Root<User> users = q.from(User.class);final Predicate condition = cb.equal(users.get("privilegeLevel);q.select(users).where(condition).orderBy(cb.asc(users.get("userId首先,從EntityManager獲得CriteriaBuilder 。 然后,獲取一個CriteriaQuery實例,將該類設置為保存結果。 在我們的例子中, User.class :
final CriteriaBuilder cb = em.getCriteriaBuilder(); final CriteriaQuery<User> q = cb.createQuery(User.class);接下來,必須設置要對其運行查詢的實體:
final Root<User> users = q.from(User.class);現在是時候設置查詢匹配條件了。 在示例代碼中,條件只是屬性privilegeLevel等于5:
final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);最后,構建查詢以在Root上添加條件。 也可以設置分組和排序選項(即,對userId設置升序):
q.select(users).where(condition).orderBy(cb.asc(users.get(“userId”)));請查看CriteriaBuilder中的不同選項。 可以在CriteriaQuery中找到分組和排序選項。
使用元模型進行編譯時檢查
請注意,我們剛剛構建的查詢需要跟蹤對象屬性名稱。 例如,要構建查詢,將使用屬性privilegeLevel的名稱。 但是,如果稍后更改屬性名稱,則代碼將編譯并且僅在運行時失敗:
final CriteriaQuery<User> q = cb.createQuery(User.class);final Root<User> users = q.from(User.class);final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);q.select(users).where(condition).orderBy(cb.asc(users.get("userId")));那不好
幸運的是,使用元模型,我們將能夠構建編譯時檢查的查詢。 可以在The Java EE6 Tutorial中找到簡短的介紹。
使用元模型,代碼將引用對象的SingularAttribute,而不是使用包含對象屬性名稱的String。 因此,如果稍后更改對象屬性,則編譯器將為我們標記該屬性。
首先,必須創建對應的元模型類( EntityType )。 盡管可以通過多種方式實現,但對于openJPA實現,最簡單的方法可能是添加一個openJPA構建標記 : -Aopenjpa.metamodel = true 。
因此,我們創建了User_類,它是User的對應元模型類:
* Generated by OpenJPA MetaModel Generator Tool.?**/ package com.wordpress.tododev.criteria.entities; import javax.persistence.metamodel.SingularAttribute; @javax.persistence.metamodel.StaticMetamodel (value=com.wordpress.tododev.criteria.entities.User.class) @javax.annotation.Generated (value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Mon Mar 04 16:47:46 CET 2013") public class User_ {public static volatile SingularAttribute<User,Boolean> active;public static volatile SingularAttribute<User,String> email;public static volatile SingularAttribute<User,String> name;public static volatile SingularAttribute<User,Integer> privilegeLevel;public static volatile SingularAttribute<User,String> userDigestedPasswd;public static volatile SingularAttribute<User,Integer> userId; }如果將此類添加到代碼庫中,則以后對User類的任何更改都不會引起注意。 而且,將自動生成的項目添加到代碼版本控制系統中不是一個好主意。
使用ant , maven或類似工具,可以添加目標以創建元模型類。 在更改JPA實體后,應執行該目標。
也可以使用IDE。 例如,對于使用Eclipse的,只需要已經提到編譯標志添加屬性- > Java的反編譯>注解處理器和的lib(JAR)包含所選擇的JPA實現第廠路內注釋處理器的注釋處理器(可能導致自動模式下的編譯問題,前提是必須在使用它的代碼之前編譯元模型類)。
讓我們向套件添加另一個測試。 這個不會提供包含屬性名稱的String,而是使用metamodel類:
@Testpublic void testUserCriteriaMetaModel(){EntityManagerFactory emf = null;EntityManager em = null;try {emf = Persistence.createEntityManagerFactory("criteria");em = emf.createEntityManager();final CriteriaBuilder cb = em.getCriteriaBuilder();final CriteriaQuery<User> q = cb.createQuery(User.class);final Metamodel m = em.getMetamodel();final Root<User> user = q.from(m.entity(User.class));final Predicate condition = cb.equal(user.get(User_.privilegeLevel), 5);q.select(user).where(condition).orderBy(cb.asc(user.get(User_.userId)));em.getTransaction().begin();List<User> result = em.createQuery(q).getResultList();em.getTransaction().commit();assertNotNull(result);assertEquals(2, result.size());assertEquals(1, (int)result.get(0).getUserId());assertEquals("Pepe", result.get(0).getName());assertEquals(3, (int)result.get(1).getUserId());assertEquals("Dolores", result.get(1).getName()); } catch (Exception e) {fail("Unexpected Exception " + e.getMessage());} finally {if (em != null)em.close();if (emf != null)emf.close();}}更相關的更改是user.get(User_.privilegeLevel)而不是users.get(“ privilegeLevel”)和 ? user.get(User_.userId)而不是 ? users.get(“ userId”)。
- 從GitHub下載源代碼。
翻譯自: https://www.javacodegeeks.com/2014/08/compile-time-checking-jpa-queries.html
jpa 手動預編譯
總結
以上是生活随笔為你收集整理的jpa 手动预编译_编译时检查JPA查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 联想电脑产品简介(联想笔记本电脑产品介绍
- 下一篇: 显示器1440*900是多少寸