jpa语法错误_JPA陷阱/错误
jpa語法錯誤
根據我在幫助團隊和進行培訓方面的經驗,這是我遇到的一些陷阱/錯誤,它們在使用JPA的基于Java的系統中引起了一些問題。
- 需要一個公共的無參數構造函數
- 始終使用雙向關聯/關系
- 將@OneToMany用于可能龐大的集合
需要一個公共的無參數構造函數
是的,JPA @Entity需要零參數(或默認的無參數)構造函數。 但這可以得到protected 。 您不必將其public 。 這樣就可以實現更好的面向對象的建模,因為您不必強制使用可公開訪問的零參數構造函數。
實體類必須具有無參數構造函數。 實體類也可以具有其他構造函數。 no-arg構造函數必須是public 或protected 。 [強調我的]
–摘自Java Persistence API 2.1規范(Oracle)的2.1節
如果要建模的實體在創建時有一些字段需要初始化,則應通過其構造函數來完成。
注意:一些JPA提供程序可以通過在構建時添加一個無參數的構造函數來克服缺失的無參數構造函數。
假設我們正在建模酒店房間預訂系統。 在其中,我們可能有諸如房間,預訂等之類的實體。預訂實體可能需要開始日期和結束日期,因為沒有停留時間來創建一個預訂實體就沒有多大意義。 在保留的構造函數中將開始日期和結束日期作為參數包括在內,將可以提供更好的模型。 保留受保護的零參數構造函數會使JPA滿意。
@Entity public class Reservation { ...public Reservation(RoomType roomType, DateRange startAndEndDates) {if (roomType == null || startAndEndDates == null) {throw new IllegalArgumentException(...);} ...}...protected Reservation() { /* as required by ORM/JPA */ } }注意: Hibernate(JPA提供程序)允許將零參數構造函數設為私有。 這使您的JPA代碼不可移植到其他JPA提供程序。
它還有助于在零參數構造函數中添加注釋,以表明它是出于JPA目的(技術基礎結構)而添加的,并且不是域所必需的(業務規則/邏輯)。
盡管我在JPA 2.1規范中找不到它,但可嵌入類也需要一個默認(無參數)構造函數。 就像實體一樣,可以將必需的無參數構造函數設為protected 。
@Embeddable public class DateRange { ...public DateRange(Date start, Date end) {if (start == null || end == null) {throw new IllegalArgumentException(...);}if (start.after(end)) {throw new IllegalArgumentException(...);} ...}...protected DateRange() { /* as required by ORM/JPA */ } }DDD示例項目還通過將no-arg構造函數設置為包范圍來隱藏no-arg構造函數(請參閱Cargo實體類,其中no-arg構造函數位于底部附近)。
始終使用雙向關聯/關系
JPA上的教學材料通常顯示出雙向關聯。 但這不是必需的。 例如,假設我們有一個包含一個或多個項目的訂單實體。
@Entity public class Order {@Id private Long id;@OneToMany private List<OrderItem> items;... }@Entity public class OrderItem {@Id private Long id;@ManyToOne private Order order;... }很高興知道JPA支持雙向關聯。 但是實際上,這成為維護的噩夢。 如果訂單項不必知道其父訂單對象,則單向關聯就足夠了(如下所示)。 ORM只需要知道如何命名多邊表中的外鍵列。 通過在關聯的一側添加@JoinColumn批注來提供此功能。
@Entity public class Order {@Id Long id;@OneToMany@JoinColumn(name="order_id", ...)private List<OrderItem> items;... }@Entity public class OrderItem {@Id private Long id;// @ManyToOne private Order order;... }由于OrderItem不再需要保留對Order實體的引用,因此使其變得單向變得更容易。
請注意,有時可能需要雙向關聯。 實際上,這種情況很少見。
這是另一個例子。 假設您有幾個引用國家/地區實體的實體(例如,人的出生地,郵寄地址等)。 顯然,這些實體將引用國家實體。 但是,國家是否必須引用所有這些不同的實體? 很有可能,不是。
@Entity public class Person {@Id Long id;@ManyToOne private Country countryOfBirth;... }@Entity public class PostalAddress {@Id private Long id;@ManyToOne private Country country;... }@Entity public class Country {@Id ...;// @OneToMany private List<Person> persons;// @OneToMany private List<PostalAddress> addresses; }所以,僅僅因為JPA支持雙向關聯, 并不意味著你必須!
使用
假設您正在建模銀行帳戶及其交易。 隨著時間的流逝,一個帳戶可以進行數千(甚至數百萬)筆交易。
@Entity public class Account {@Id Long id;@OneToMany@JoinColumn(name="account_id", ...)private List<AccountTransaction> transactions;... }@Entity public class AccountTransaction {@Id Long id;... }對于只有少量交易的帳戶,似乎沒有任何問題。 但是隨著時間的流逝,當一個帳戶包含成千上萬個(如果不是上百萬個)交易時,您很可能會遇到內存不足的錯誤。 那么,有什么更好的映射方法呢?
如果不能確保關聯的多面中的最大元素數都可以全部加載到內存中,則最好在@ManyToOne的另一側使用@ManyToOne 。
@Entity public class Account {@Id Long id;// @OneToMany private List<AccountTransaction> transactions;... }@Entity public class AccountTransaction {@Id Long id;@ManyToOneprivate Account account;...public AccountTransaction(Account account, ...) {...}protected AccountTransaction() { /* as required by ORM/JPA */ } }要檢索一個帳戶可能數千(如果不是幾百萬)的交易,請使用支持分頁的存儲庫。
@Transactional public interface AccountTransactionRepository {Page<AccountTransaction> findByAccount(Long accountId, int offset, int pageSize);... }要支持分頁,請使用Query對象的setFirstResult(int)和setMaxResults(int)方法。
摘要
我希望這些說明可以幫助開發人員避免犯這些錯誤。 總結一下:
- 要求公眾。 JPA要求的無參數構造函數可以設為public或protected 。 如果需要,可以考慮對其進行protected 。
- 一直使用 考慮單向而不是雙向關聯/關系。
- 使用 避免使用@OneToMany收集可能龐大的集合。 考慮@ManyToOne映射關聯/關系的@ManyToOne端,并支持分頁。
翻譯自: https://www.javacodegeeks.com/2016/02/jpa-pitfalls-mistakes.html
jpa語法錯誤
總結
以上是生活随笔為你收集整理的jpa语法错误_JPA陷阱/错误的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javafx_JavaFX在这里留下来!
- 下一篇: DDOS论坛(ddos交易论坛)