日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java jpa 规范_Java:在JPA中使用规范模式

發(fā)布時間:2023/12/3 java 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java jpa 规范_Java:在JPA中使用规范模式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

java jpa 規(guī)范

本文是在Java中使用規(guī)范模式的簡介。 我們還將看到如何將經(jīng)典規(guī)范與JPA Criteria查詢結(jié)合使用,以從關(guān)系數(shù)據(jù)庫中檢索對象。

在本文中,我們將使用以下Poll類作為創(chuàng)建規(guī)范的示例實體。 它表示具有開始和結(jié)束日期的民意調(diào)查。 在這兩個日期之間的時間中,用戶可以在不同的選擇之間進行投票。 到達結(jié)束日期之前,管理員還可以鎖定民意調(diào)查。 在這種情況下,將設(shè)置鎖定日期。

@Entity public?class?Poll?{?@Id@GeneratedValueprivate?long?id;private?DateTime?startDate;?private?DateTime?endDate;private?DateTime?lockDate;@OneToMany(cascade?=?CascadeType.ALL)private?List<Vote>?votes?=?new?ArrayList<>();}

為了獲得更好的可讀性,我跳過了用于映射此示例中不需要的Joda DateTime實例和字段的getter,setter,JPA批注(例如民意調(diào)查中提出的問題)。

現(xiàn)在假設(shè)我們要實現(xiàn)兩個約束:

  • 如果未鎖定且startDate <now <endDate,則輪詢當(dāng)前正在運行
  • 如果民意調(diào)查的投票數(shù)超過100并且未鎖定,則該投票很受歡迎

我們可以從向Poll添加適當(dāng)?shù)姆椒ㄩ_始,例如:poll.isCurrentlyRunning()。 另外,我們可以使用類似pollService.isCurrentlyRunning(poll)的服務(wù)方法。 但是,我們還希望能夠查詢數(shù)據(jù)庫以獲取所有當(dāng)前正在運行的民意調(diào)查。 因此,我們可以添加DAO或存儲庫方法,例如pollRepository.findAllCurrentlyRunningPolls()。

如果采用這種方式,我們將在兩個不同的位置兩次實現(xiàn)isCurrentlyRunning約束。 如果我們要結(jié)合約束,事情就會變得更糟。 如果我們想查詢數(shù)據(jù)庫以獲取當(dāng)前正在運行的所有流行民意測驗的列表怎么辦?

這是規(guī)范模式派上用場的地方。 使用規(guī)范模式時,我們將業(yè)務(wù)規(guī)則移到稱為規(guī)范的額外類中。

首先,我們創(chuàng)建一個簡單的界面和一個抽象類:

public?interface?Specification<T>?{??boolean?isSatisfiedBy(T?t);??Predicate?toPredicate(Root<T>?root,?CriteriaBuilder?cb);Class<T>?getType(); }abstract?public?class?AbstractSpecification<T>?implements?Specification<T>?{@Overridepublic?boolean?isSatisfiedBy(T?t)?{throw?new?NotImplementedException();}??@Overridepublic?Predicate?toPredicate(Root<T>?poll,?CriteriaBuilder?cb)?{throw?new?NotImplementedException();}@Overridepublic?Class<T>?getType()?{ParameterizedType?type?=?(ParameterizedType)?this.getClass().getGenericSuperclass();return (Class<T>) type.getActualTypeArguments()[0];} }

請暫時忽略帶有神秘的getType()方法的AbstractSpecification <T>類(我們稍后再介紹)。

規(guī)范的中心部分是isSatisfiedBy()方法,該方法用于檢查對象是否滿足規(guī)范。 toPredicate()是我們在本示例中使用的另一種方法,用于以javax.persistence.criteria.Predicate實例的形式返回約束,該約束可用于查詢數(shù)據(jù)庫。

對于每個約束,我們創(chuàng)建一個新的規(guī)范類,該類擴展AbstractSpecification <T>并實現(xiàn)isSatisfiedBy()和toPredicate()。

檢查輪詢是否正在運行的規(guī)范實現(xiàn)如下所示:

public?class?IsCurrentlyRunning?extends?AbstractSpecification<Poll>?{@Overridepublic?boolean?isSatisfiedBy(Poll?poll)?{return?poll.getStartDate().isBeforeNow()?&&?poll.getEndDate().isAfterNow()?&&?poll.getLockDate()?==?null;}@Overridepublic?Predicate?toPredicate(Root<Poll>?poll,?CriteriaBuilder?cb)?{DateTime?now?=?new?DateTime();return?cb.and(cb.lessThan(poll.get(Poll_.startDate),?now),cb.greaterThan(poll.get(Poll_.endDate),?now),cb.isNull(poll.get(Poll_.lockDate)));} }

在isSatisfiedBy()中,我們檢查傳遞的對象是否與約束匹配。 在toPredicate()中,我們使用JPA的CriteriaBuilder構(gòu)造謂詞。 稍后,我們將使用結(jié)果謂詞實例來構(gòu)建用于查詢數(shù)據(jù)庫的CriteriaQuery。

用于檢查民意調(diào)查是否受歡迎的規(guī)范看起來類似:

public?class?IsPopular?extends?AbstractSpecification<Poll>?{@Overridepublic?boolean?isSatisfiedBy(Poll?poll)?{return?poll.getLockDate()?==?null?&&?poll.getVotes().size()?> 100;}??@Overridepublic?Predicate?toPredicate(Root<Poll>?poll,?CriteriaBuilder?cb)?{return?cb.and(cb.isNull(poll.get(Poll_.lockDate)),cb.greaterThan(cb.size(poll.get(Poll_.votes)),?5));} }

如果現(xiàn)在要測試Poll實例是否符合以下約束之一,則可以使用我們新創(chuàng)建的規(guī)范:

boolean isPopular = new?IsPopular().isSatisfiedBy(poll); boolean isCurrentlyRunning = new?IsCurrentlyRunning().isSatisfiedBy(poll);

為了查詢數(shù)據(jù)庫,我們需要擴展DAO /存儲庫以支持規(guī)范。 看起來可能如下所示:

public?class?PollRepository?{private?EntityManager?entityManager?=?...public?<T>?List<T>?findAllBySpecification(Specification<T>?specification)?{CriteriaBuilder?criteriaBuilder?=?entityManager.getCriteriaBuilder();//?use?specification.getType()?to?create?a?Root<T>?instanceCriteriaQuery<T>?criteriaQuery?=?criteriaBuilder.createQuery(specification.getType());Root<T>?root?=?criteriaQuery.from(specification.getType());//?get?predicate?from?specificationPredicate?predicate?=?specification.toPredicate(root,?criteriaBuilder);// set predicate and execute querycriteriaQuery.where(predicate);return?entityManager.createQuery(criteriaQuery).getResultList();} }

在這里,我們最終使用在AbstractSpecification <T>中實現(xiàn)的getType()方法來創(chuàng)建CriteriaQuery <T>和Root <T>實例。 getType()返回由子類定義的AbstractSpecification <T>實例的泛型類型。 對于IsPopular和IsCurrentlyRunning,它返回Poll類。 如果沒有g(shù)etType(),我們將不得不在我們創(chuàng)建的每個規(guī)范的toPredicate()內(nèi)創(chuàng)建CriteriaQuery <T>和Root <T>實例。 因此,減少規(guī)范內(nèi)的樣板代碼只是一個小幫手。 如果您想出更好的方法,請隨時用自己的實現(xiàn)替換它。

現(xiàn)在,我們可以使用我們的存儲庫來查詢數(shù)據(jù)庫以查找與特定規(guī)范匹配的民意測驗:

List<Poll>?popularPolls?=?pollRepository.findAllBySpecification(new?IsPopular()); List<Poll>?currentlyRunningPolls?=?pollRepository.findAllBySpecification(new?IsCurrentlyRunning());

在這一點上,規(guī)范是唯一包含約束定義的組件。 我們可以使用它來查詢數(shù)據(jù)庫或檢查對象是否滿足必需的規(guī)則。

但是,仍然存在一個問題:我們?nèi)绾谓Y(jié)合兩個或更多個約束? 例如,我們想查詢數(shù)據(jù)庫以獲取所有仍在運行的流行民意調(diào)查。

答案是復(fù)合設(shè)計模式的一種變化,稱為復(fù)合規(guī)格。 使用復(fù)合規(guī)范,我們可以以不同方式組合規(guī)范。

要查詢數(shù)據(jù)庫中所有正在運行和流行的池,我們需要使用邏輯和操作將isCurrentlyRunning與isPopular規(guī)范結(jié)合在一起。 讓我們?yōu)榇藙?chuàng)建另一個規(guī)范。 我們將其命名為AndSpecification:

public?class?AndSpecification<T>?extends?AbstractSpecification<T>?{private?Specification<T>?first;private?Specification<T>?second;public?AndSpecification(Specification<T>?first,?Specification<T>?second)?{this.first?=?first;this.second?=?second;}@Overridepublic?boolean?isSatisfiedBy(T?t)?{return?first.isSatisfiedBy(t)?&&?second.isSatisfiedBy(t);}@Overridepublic?Predicate?toPredicate(Root<T>?root,?CriteriaBuilder?cb)?{return?cb.and(first.toPredicate(root,?cb),?second.toPredicate(root,?cb));}@Overridepublic?Class<T>?getType()?{return?first.getType();} }

AndSpecification是從其他兩個規(guī)范中創(chuàng)建的。 在isSatisfiedBy()和toPredicate()中,我們通過邏輯和運算返回兩個規(guī)范的結(jié)果。

我們可以像這樣使用我們的新規(guī)范:

Specification<Poll>?popularAndRunning?=?new?AndSpecification<>(new?IsPopular(),?new?IsCurrentlyRunning()); List<Poll>?polls?=?myRepository.findAllBySpecification(popularAndRunning);

為了提高可讀性,我們可以在規(guī)范接口中添加and()方法:

public?interface?Specification<T>?{Specification<T>?and(Specification<T>?other);//?other?methods }

并在我們的抽象實現(xiàn)中實現(xiàn)它:

abstract?public?class?AbstractSpecification<T>?implements?Specification<T>?{@Overridepublic?Specification<T>?and(Specification<T>?other)?{return?new?AndSpecification<>(this,?other);}//?other?methods }

現(xiàn)在,我們可以使用and()方法鏈接多個規(guī)范:

Specification<Poll>?popularAndRunning?=?new?IsPopular().and(new?IsCurrentlyRunning()); boolean?isPopularAndRunning?=?popularAndRunning.isSatisfiedBy(poll); List<Poll>?polls?=?myRepository.findAllBySpecification(popularAndRunning);

在需要時,我們可以輕松地通過其他復(fù)合規(guī)范(例如OrSpecification或NotSpecification)進一步擴展該規(guī)范。

結(jié)論

使用規(guī)范模式時,我們將業(yè)務(wù)規(guī)則移到單獨的規(guī)范類中。 通過使用復(fù)合規(guī)范,可以輕松組合這些規(guī)范類。 通常,規(guī)范可以提高可重用性和可維護性。 另外,規(guī)格可以輕松進行單元測試。 有關(guān)規(guī)范模式的更多詳細信息,我推薦Eric Evans和Martin Fowler 撰寫的這篇文章 。

  • 您可以在GitHub上找到此示例項目的源代碼。

參考: Java:在mscharhag,Programming and Stuff博客上,我們的JCG合作伙伴 Michael Scharhag 使用了JPA規(guī)范模式 。

翻譯自: https://www.javacodegeeks.com/2014/01/java-using-the-specification-pattern-with-jpa.html

java jpa 規(guī)范

總結(jié)

以上是生活随笔為你收集整理的java jpa 规范_Java:在JPA中使用规范模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。