[英]Do we need JPA Relationships and Criteria API
背景:
我們正在使用傳統的自定義構建查詢生成器,該查詢生成器基本上具有所有與查詢相關的API。 從概念上講,它在某種程度上等同於JPA標准API。 自從我們從EJB 2遷移到EJB 3以來,它對元數據的EJB 2 XML的依賴使我們非常困擾。 問題之一是,僅僅為了查詢生成器,我們不得不維護/更新EJB 2 XML文件。
作為從EJB 2到EJB 3遷移的一部分,我們為所有表創建了Entity類。 但是,我們沒有在實體之間添加關系。
現在,我們正在尋找擺脫它的方法,並且幾乎我們決定使用JPA。
幾個想法:
鑒於Criteria API要求實體關系,我有以下想法
問題:
也就是說,從廣義上講,實體關系似乎弊大於利。
任何想法都非常感謝。
提前致謝,
拉克什
對於此問題,什么方案的Criteria API勝過JPQL(命名和NamedNative查詢)-
我們的項目中有寧靜的Web服務,在這種情況下,我們需要按一些屬性進行過濾。 如果使用查詢方法作為過濾參數的增加,您的查詢也會增加。 在這種情況下,標准api更好。
在下面的示例中,我們有2個查詢參數,因此兩種方法都不錯。 但是,如果您有4或5個過濾查詢參數標准api是最佳選擇。
public List<AccountEntity> createCriteriaQuery(final List<String> accountIdList,
final MultiValueMap<String, String> allRequestParams) {
final EntityManager entityManager = entityManagerFactory.createEntityManager();
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final CriteriaQuery<AccountEntity> cq = cb.createQuery(AccountEntity.class);
final Root<AccountEntity> accountEntity = cq.from(AccountEntity.class);
final Join<AccountEntity, PlanEntity> account = accountEntity.join(AccountEntity_.planEntity);
final List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(accountEntity.get(AccountEntity_.id).in(accountIdList));
if (!allRequestParams.isEmpty()) {
if (allRequestParams.containsKey(ApplicationConstants.QUERYPARAM_ACCOUNTTYPE)) {
String accountType = allRequestParams.get(ApplicationConstants.QUERYPARAM_ACCOUNTTYPE).get(0);
if (accountType.equalsIgnoreCase(ApplicationConstants.ACCOUNTTYPE_POINT)) {
accountType = ApplicationConstants.ACCOUNTTYPE_PTS;
}
predicates.add(cb.equal(accountEntity.get(AccountEntity_.accounttype), accountType));
}
if (allRequestParams.containsKey(ApplicationConstants.QUERYPARAM_PLANNAME)) {
final String planName = allRequestParams.get(ApplicationConstants.QUERYPARAM_PLANNAME).get(0);
predicates.add(cb.like(account.get(PlanEntity_.name), "%" + planName + "%"));
}
}
cq.select(accountEntity).where(predicates.toArray(new Predicate[] {}));
cq.orderBy(cb.asc(account.get(PlanEntity_.name)));
final TypedQuery<AccountEntity> qry = entityManager.createQuery(cq);
return qry.getResultList();
}
實體關系伴隨着決定懶惰或渴望的負擔。 雖然急於加載通常會導致性能問題,但延遲加載會強制使用Open Session In View模式,該模式存在很多問題
您可能使JPA變得比所需的復雜。 實體是通過例外配置的,因此在很多時候,明智的默認值會應用於您的關系中(例如,懶惰一對多,渴望一對一)。 如果您的概要分析確定了與實體加載相關的性能問題,則只需指定急切或延遲映射。
特別是,如果關系經常被頻繁加載,則惰性映射會導致性能問題,這將導致額外的數據庫訪問。 如果不使用這種關系,則渴望映射可能會類似地導致性能問題。 這些是訪問高度規范化數據時始終存在的問題,而不僅僅是JPA的問題。
盡管Relationships and Criteria API使開發人員免受數據庫SQL的攻擊,但是在很大程度上由於性能影響的風險遠遠超過了該影響,因為輕微的編程錯誤會導致大量DB sql查詢。 為了避免這種情況,開發人員必須使用數據庫,這使數據庫屏蔽成為一個問題
我認為,JPA的風險收益比被誇大了。 雖然有時可以通過使用自己的JDBC調用來獲得更好的性能,但是通常會誇大了性能優勢,因此必須相對於ORM的其他優勢進行權衡。 我傾向於認為“ ORM是您的朋友”。
正如預期的那樣,業務邏輯會照顧哪個實體先於另一個實體存在。 使用CascadeType將其移動到Entity層似乎沒有任何優勢。
級聯是一個選項,您可以在操作鏈接與關系類型密切相關的適當實體中指定。 沒有人時就沒有優勢。
JPQL(NamedQueries和NamedNativeQueries)似乎都與Criteria API一樣強大
它們只是可以用來完成同一件事的不同范例。 Criteria API是一種簡單的DSL,允許您通過使用方法調用構建一系列Java對象來對實體對象構造查詢。 JPQL查詢是使用字符串構建的。
大多數Criteria API資料都聲稱Criteria API在過濾方面是最好的。 但是,在參數數量和表聯接數量更多的情況下,這似乎並不正確。
JPQL和Criteria API是完成同一件事的不同方式。 它們是比沖突更具互補性的技術。
實體關系將使您不必再單獨調用存儲庫,而這會在延遲加載時自動發生。 同樣,您也不希望將實體對象傳遞給Controller,因為它們將能夠在業務邏輯之外修改您的實體。 您想給他們數據,而不是給數據庫的連接。 而且,如果這樣做,則無需在控制器中打開會話。
使用NamedQueries和Criteria,您真的想在NamedQueries無法使用時使用Criteria,即,當您有一個確定的謂詞時,請使用NamedQuery。 但是,如果您的謂詞不固定,例如,當訂單類型為貨到付款時,您在查詢中添加了價格限制,則必須通過條件。
說了這么多,恕我直言,避免使用標准和關系讓您容易出錯的想法是有缺陷的。 無論如何,您在SQL上都可能遇到相同的錯誤,這就是測試的全部目的。
級聯是一種在某些情況下有效的想法,但不一定在所有情況下都有用。 如果您想明確地級聯,那沒什么大不了的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.