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

java jpa 规范

本文是在Java中使用规范模式的简介。 我们还将看到如何将经典规范与JPA Criteria查询结合使用,以从关系数据库中检索对象。

在本文中,我们将使用以下Poll类作为创建规范的示例实体。 它表示具有开始和结束日期的民意调查。 在这两个日期之间的时间中,用户可以在不同的选择之间进行投票。 到达结束日期之前,管理员还可以锁定民意调查。 在这种情况下,将设置锁定日期。

@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批注(例如民意调查中提出的问题)。

现在假设我们要实现两个约束:

  • 如果未锁定且startDate <now <endDate,则轮询当前正在运行
  • 如果民意调查的投票数超过100并且未锁定,则该投票很受欢迎

我们可以从向Poll添加适当的方法开始,例如:poll.isCurrentlyRunning()。 另外,我们可以使用类似pollService.isCurrentlyRunning(poll)的服务方法。 但是,我们还希望能够查询数据库以获取所有当前正在运行的民意调查。 因此,我们可以添加DAO或存储库方法,例如pollRepository.findAllCurrentlyRunningPolls()。

如果采用这种方式,我们将在两个不同的位置两次实现isCurrentlyRunning约束。 如果我们要结合约束,事情就会变得更糟。 如果我们想查询数据库以获取当前正在运行的所有流行民意测验的列表怎么办?

这是规范模式派上用场的地方。 使用规范模式时,我们将业务规则移到称为规范的额外类中。

首先,我们创建一个简单的界面和一个抽象类:

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>类(我们稍后再介绍)。

规范的中心部分是isSatisfiedBy()方法,该方法用于检查对象是否满足规范。 toPredicate()是我们在本示例中使用的另一种方法,用于以javax.persistence.criteria.Predicate实例的形式返回约束,该约束可用于查询数据库。

对于每个约束,我们创建一个新的规范类,该类扩展AbstractSpecification <T>并实现isSatisfiedBy()和toPredicate()。

检查轮询是否正在运行的规范实现如下所示:

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构造谓词。 稍后,我们将使用结果谓词实例来构建用于查询数据库的CriteriaQuery。

用于检查民意调查是否受欢迎的规范看起来类似:

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));}
}

如果现在要测试Poll实例是否符合以下约束之一,则可以使用我们新创建的规范:

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

为了查询数据库,我们需要扩展DAO /存储库以支持规范。 看起来可能如下所示:

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>中实现的getType()方法来创建CriteriaQuery <T>和Root <T>实例。 getType()返回由子类定义的AbstractSpecification <T>实例的泛型类型。 对于IsPopular和IsCurrentlyRunning,它返回Poll类。 如果没有getType(),我们将不得不在我们创建的每个规范的toPredicate()内创建CriteriaQuery <T>和Root <T>实例。 因此,减少规范内的样板代码只是一个小帮手。 如果您想出更好的方法,请随时用自己的实现替换它。

现在,我们可以使用我们的存储库来查询数据库以查找与特定规范匹配的民意测验:

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

在这一点上,规范是唯一包含约束定义的组件。 我们可以使用它来查询数据库或检查对象是否满足必需的规则。

但是,仍然存在一个问题:我们如何结合两个或更多个约束? 例如,我们想查询数据库以获取所有仍在运行的流行民意调查。

答案是复合设计模式的一种变化,称为复合规格。 使用复合规范,我们可以以不同方式组合规范。

要查询数据库中所有正在运行和流行的池,我们需要使用逻辑和操作将isCurrentlyRunningisPopular规范结合在一起。 让我们为此创建另一个规范。 我们将其命名为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是从其他两个规范中创建的。 在isSatisfiedBy()和toPredicate()中,我们通过逻辑和运算返回两个规范的结果。

我们可以像这样使用我们的新规范:

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

为了提高可读性,我们可以在规范接口中添加and()方法:

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

并在我们的抽象实现中实现它:

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

现在,我们可以使用and()方法链接多个规范:

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

在需要时,我们可以轻松地通过其他复合规范(例如OrSpecification或NotSpecification)进一步扩展该规范。

结论

使用规范模式时,我们将业务规则移到单独的规范类中。 通过使用复合规范,可以轻松组合这些规范类。 通常,规范可以提高可重用性和可维护性。 另外,规格可以轻松进行单元测试。 有关规范模式的更多详细信息,我推荐Eric Evans和Martin Fowler 撰写的这篇文章 。

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

参考: Java:在mscharhag,Programming and Stuff博客上,我们的JCG合作伙伴 Michael Scharhag 使用了JPA规范模式 。

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

java jpa 规范

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/344702.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01数字基带信号及其频谱特性

S1 数字基带信号及其频谱特性 一、分类 1、单极性不归零波形 优点&#xff1a;电脉冲之间无间隔&#xff0c;极性单一&#xff0c;易于用TTL&#xff0c;CMOS电路产生&#xff1b; 缺点&#xff1a; a) 有直流成份&#xff1b;判决电平不能稳定在最佳的电平&#xff0c;抗噪声…

【渝粤教育】电大中专电商运营实操 作业 题库

1.电子商务最重要的是&#xff08; &#xff09; A.商务 B.网站 C.货物 D.信息技术 正确 正确答案&#xff1a;左边查询 学生答案&#xff1a;A 2.目前菜鸟网络依赖大数据和云计算已实现了哪些功能&#xff08; &#xff09; A.自动化仓库 B.智能发货 C.物流云加速 D.以上都正确…

人工智能英语学习笔记

基础篇单词 mythology n. ancient myths in general; ideas that many people think are true but that do not exist or are false 神话 Examples: A satyr is half man and half goat in Greek and Roman mythology. 在希腊和罗马神话中&#xff0c;森林之神是半人半羊的样子…

【渝粤教育】电大中专电子商务网站建设与维护 (24)作业 题库

1.阿里巴巴网站的不足不包括&#xff08; &#xff09; A.网站定位不当 B.客户过于庞大&#xff0c;往往不重视或忽略了个别小企业基本服务 C.信息冗余 D.“诚信通”的诚信问题 错误 正确答案&#xff1a;左边查询 学生答案&#xff1a;未作答 2.阿里巴巴采用国际化的网站建设方…

CSDN公式编辑(latex语言应用)整理

在线Latex公式编辑器 latex语法指南 一、常用规则 1、编辑公式时&#xff0c;公式显示在两个$$之间。 $ 公式 $ &#xff1a;可写在句中&#xff0c;如me>smartnicehealthyme>smartnicehealthyme>smartnicehealthy $ $ 公式 $ $ &#xff1a;比较大&#xff0c;如me…

API网关正在经历身份危机

这些年来&#xff0c;API网关正在经历一些身份危机 。 它们是否是集中的共享资源&#xff0c;以促进对外部实体的API公开和治理&#xff1f; 它们是集群入口哨兵&#xff0c;可以严格控制哪些用户流量进入或离开集群吗&#xff1f; 还是他们根据自己拥有的客户端类型&#x…

【渝粤教育】广东开放大学 PHP动态网站设计 形成性考核 (48)

选择题 题目&#xff1a;下列说法不正确的是____________。 答案&#xff1a;看左侧 题目&#xff1a;PHP是一种跨平台、的网页脚本语言。 答案&#xff1a;看左侧 题目&#xff1a;PHP网站可称为。 答案&#xff1a;看左侧 题目&#xff1a;PHP网页文件的文件扩展名为________…

通信原理速学02:随机过程

模块1 随机过程 随机过程与样本函数 随机过程指一类随时间做随机变化的过程&#xff0c;用ξ(t)表示&#xff0c;其值不确定&#xff0c;无法用确切的时间函数描述。 随机过程的每一次实现&#xff0c;就称为一次样本函数ξi(t)&#xff0c;随机过程是所有样本函数的集合。 基…

【渝粤教育】广东开放大学 企业财务报表分析 形成性考核 (26)

选择题 题目&#xff1a;行业平均水平标准一般可用于&#xff08;&#xff09; 答案&#xff1a;看左侧 题目&#xff1a;确定影响因素、衡量其影响程度、查明指标变动原因的分析方法是&#xff08;&#xff09;。 答案&#xff1a;看左侧 题目&#xff1a;在企业编制的会计报表…

Verilog基本语法初学

一、语言要素 (一)概述 1、空白符&#xff08;White Space&#xff09; 空格、换行、换页、Tab等&#xff1b; 是代码错落有致&#xff0c;提高可读性。 2、注释&#xff08;Comment&#xff09; 单行注释&#xff1a;“ // ”&#xff1b; 多行注释&#xff1a;“ /* ”~“ …

spring 事务持久性_项目学生:Spring数据的持久性

spring 事务持久性这是Project Student的一部分。 其他职位包括带有Jersey的Webservice Client&#xff0c;带有Jersey的 Webservice Server和业务层 。 RESTful webapp onion的最后一层是持久层。 持久层有两种哲学。 一个阵营将数据库视为一个简单的存储&#xff0c;并希望…

【渝粤教育】广东开放大学 商法 形成性考核 (40)

选择题 题目&#xff1a;2020年1月1日&#xff0c;小李到广州A超市购物&#xff0c;发现A超市设有服务台和自助寄存柜。考虑到服务台需要排队&#xff0c;为节省时间&#xff0c;小李根据A超市对自助寄存柜的使用方法及物品的保管等问题的明确指引和警示&#xff0c;进行操作&a…

力扣算法001_两数之和

1、 两数之和 给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素不能使用两遍。 示例: 给定 nums [2, 7, 11…

使用Apache Ignite瘦客户端– Apache Ignite内部博客

从2.4.0版本开始&#xff0c;Apache Ignite引入了一种新的连接到Ignite群集的方法&#xff0c;该方法允许与Ignite群集进行通信而无需启动Ignite客户端节点。 从历史上看&#xff0c;Apache Ignite提供了客户端和服务器节点两个概念。 点燃旨在用作轻量级模式的客户端节点&…

【渝粤教育】广东开放大学 岭南文化概论 形成性考核 (45)

选择题 题目&#xff1a; &#xff08;&#xff09;是岭南文化中最有响并最具典型性的文化。 选择一项&#xff1a; 答案&#xff1a;看左侧 题目&#xff1a; &#xff08;&#xff09;是岭南文化中最有响并最具典型性的文化。 选择一项&#xff1a; 答案&#xff1a;看左侧…

【渝粤教育】广东开放大学 数据采集技术 形成性考核 (29)

选择题 题目&#xff1a;GET和POST的区别&#xff0c;以下说法不正确的有&#xff08;&#xff09;。 题目&#xff1a;以下属于HTTP协议的主要特点的是&#xff08;&#xff09;。 题目&#xff1a;增量式爬虫中的&#xff08;&#xff09;指的是&#xff1a;爬虫以相同的频率…

2020-12-15通信原理

1、随机过程是一类随时间作随机变化的过程&#xff0c;不能用确切的时间函数描述。 不同角度理解&#xff1a;&#xff08;1&#xff09;对应不同随机试验结果的时间过程的集合&#xff1b;&#xff08;2&#xff09;随机过程是随机变量概念的延伸。 可以把随机过程看作是在时间…

【渝粤教育】广东开放大学 机械制造基础 形成性考核 (51)

选择题 题目&#xff1a;退火一般安排在 ( ) 题目&#xff1a;从蠕墨铸铁的牌号上可以看出其硬度和冲击韧性。 题目&#xff1a;钎焊接头的主要缺点是&#xff08; &#xff09; 题目&#xff1a;高碳钢淬火后回火时,随回火温度升高其&#xff08; &#xff09; 题目&#xff1…

【渝粤教育】广东开放大学 电子支付与安全 形成性考核 (59)

选择题 题目&#xff1a;直接参与者&#xff1a;商行和央行&#xff08;商行以其不通层次的管辖银行在相应层次的央行开设清算帐户&#xff09; 答案&#xff1a;看左侧 题目&#xff1a;支付系统全国处理中心是控制支付系统运行&#xff0c;管理国家金融网络通信、接收、结算、…

java 将光标移至行首_Java:将条件移至消息文件

java 将光标移至行首Java类ResourceBundle和MessageFormat提供了一个很好的工具集&#xff0c;用于解决Java应用程序内部的本地化消息。 这篇文章提供了一个小示例&#xff0c;说明如何使用ChoiceFormat将与消息相关的简单条件从Java代码移动到消息文件中。 如果您已经知道Choi…