项目学生:JPA标准查询

这是Project Student的一部分。 其他职位包括带有Jersey的Webservice Client,带有Jersey的 Webservice Server , 业务层 , 具有Spring Data的持久性 ,分片集成测试数据和Webservice Integration 。

我们已经介绍了CRUD的基本操作,但是并没有花太多时间。 Spring Data使包含基本搜索变得容易,但是拥有其他标准选项也很重要。 JPA标准查询是最重要的查询之一。

Spring Data JPA教程– JPA Criteria Queries [http://www.petrikainulainen.net]是对该材料的很好介绍。

设计决策

JPA标准 –我使用的是JPA标准搜索,而不是querydsl。 稍后我将返回querydsl。

局限性

违反封装 –此设计需要打破使每个层完全不了解其他层的实现细节的体系结构目标。 这是一个非常小的违反行为-仅JPA规范-我们仍然必须处理分页。 将它们放在一起,我觉得此时过分担心这个还为时过早。

Web服务 -不更新web服务客户端和服务器。 同样,我们仍然必须处理分页,并且无论如何我们现在要做的任何事情都必须更改。

重构先前的工作

我对以前的工作有三点改变。

findCoursesByTestRun()

我已经定义了方法:

List findCoursesByTestRun(TestRun testRun);

在课程库中。 那没有预期的效果。 我需要的是

List findCoursesByTestRun_Uuid(String uuid);

对调用代码进行适当的更改。 或者,您可以只使用下面讨论的JPA标准查询。

FinderService和ManagerService

这来自Jumpstart网站上的研究。 作者将标准服务接口分为两部分:

  • FinderService –只读操作(搜索)
  • ManagerService –读写操作(创建,更新,删除)

这很有道理,例如,当我们可以在类与方法级别上进行操作时,通过AOP添加行为会容易得多。 我在现有代码中做了适当的更改。

查找错误

我已经修复了FindBugs发现的许多问题。

元数据

我们首先启用对持久对象的元数据访问权限。 这使我们能够创建可以通过JPA实现进行优化的查询。

import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;@StaticMetamodel(Course.class)
public class Course_ {public static volatile SingularAttribute<Course, TestRun> testRun;
}

@StaticMetamodel(TestRun.class)
public class TestRun_ {public static volatile SingularAttribute<TestRun, String> uuid;
}

由于约定优于配置,因此需要类的名称。

  • 有关此功能的讨论,请参见静态元数据 [jboss.org]。

技术指标

现在,我们可以使用现在可用的元数据创建查询规范。 这是一个稍微复杂的查询,因为我们需要深入研究结构。 (由于testrun uuid用作外键,因此这不需要实际的联接。)

public class CourseSpecifications {/*** Creates a specification used to find courses with the specified testUuid.* * @param testRun* @return*/public static Specification<Course> testRunIs(final TestRun testRun) {return new Specification<Course>() {@Overridepublic Predicate toPredicate(Root<Course> courseRoot, CriteriaQuery<?> query, CriteriaBuilder cb) {Predicate p = null;if (testRun == null || testRun.getUuid() == null) {p = cb.isNull(courseRoot.<Course_> get("testRun"));} else {p = cb.equal(courseRoot.<Course_> get("testRun").<TestRun_> get("uuid"), testRun.getUuid());}return p;}};}
}

一些文档建议我可以使用get(Course_.testRun)代替get(“ testRun”),但是eclipse在get()方法上将其标记为类型冲突。 你的旅费可能会改变。

Spring数据仓库

我们必须告诉Spring Data我们正在使用JPA Criteria查询。 这是通过扩展JpaSpecificationExecutor接口来完成的。

@Repository
public interface CourseRepository extends JpaRepository<Course, Integer>,JpaSpecificationExecutor<Course> {Course findCourseByUuid(String uuid);List findCoursesByTestRunUuid(String uuid);
}

FinderService实施

现在,我们可以在服务实现中使用JPA规范。 如上所述,使用JPA标准规范违反了封装。

import static com.invariantproperties.sandbox.student.specification.CourseSpecifications.testRunIs;@Service
public class CourseFinderServiceImpl implements CourseFinderService {@Resourceprivate CourseRepository courseRepository;/*** @see com.invariantproperties.sandbox.student.business.FinderService#*      count()*/@Transactional(readOnly = true)@Overridepublic long count() {return countByTestRun(null);}/*** @see com.invariantproperties.sandbox.student.business.FinderService#*      countByTestRun(com.invariantproperties.sandbox.student.domain.TestRun)*/@Transactional(readOnly = true)@Overridepublic long countByTestRun(TestRun testRun) {long count = 0;try {count = courseRepository.count(testRunIs(testRun));} catch (DataAccessException e) {if (!(e instanceof UnitTestException)) {log.info("internal error retrieving classroom count by " + testRun, e);}throw new PersistenceException("unable to count classrooms by " + testRun, e, 0);}return count;}/*** @see com.invariantproperties.sandbox.student.business.CourseFinderService#*      findAllCourses()*/@Transactional(readOnly = true)@Overridepublic List<Course> findAllCourses() {return findCoursesByTestRun(null);}/*** @see com.invariantproperties.sandbox.student.business.CourseFinderService#*      findCoursesByTestRun(java.lang.String)*/@Transactional(readOnly = true)@Overridepublic List<Course> findCoursesByTestRun(TestRun testRun) {List<Course> courses = null;try {courses = courseRepository.findAll(testRunIs(testRun));} catch (DataAccessException e) {if (!(e instanceof UnitTestException)) {log.info("error loading list of courses: " + e.getMessage(), e);}throw new PersistenceException("unable to get list of courses.", e);}return courses;}....
}

单元测试

我们的单元测试需要稍做更改才能使用规范。

public class CourseFinderServiceImplTest {private final Class<Specification<Course>> sClass = null;@Testpublic void testCount() {final long expected = 3;final CourseRepository repository = Mockito.mock(CourseRepository.class);when(repository.count(any(sClass))).thenReturn(expected);final CourseFinderService service = new CourseFinderServiceImpl(repository);final long actual = service.count();assertEquals(expected, actual);}@Testpublic void testCountByTestRun() {final long expected = 3;final TestRun testRun = new TestRun();final CourseRepository repository = Mockito.mock(CourseRepository.class);when(repository.count(any(sClass))).thenReturn(expected);final CourseFinderService service = new CourseFinderServiceImpl(repository);final long actual = service.countByTestRun(testRun);assertEquals(expected, actual);}@Test(expected = PersistenceException.class)public void testCountError() {final CourseRepository repository = Mockito.mock(CourseRepository.class);when(repository.count(any(sClass))).thenThrow(new UnitTestException());final CourseFinderService service = new CourseFinderServiceImpl(repository);service.count();}@Testpublic void testFindAllCourses() {final List<Course> expected = Collections.emptyList();final CourseRepository repository = Mockito.mock(CourseRepository.class);when(repository.findAll(any(sClass))).thenReturn(expected);final CourseFinderService service = new CourseFinderServiceImpl(repository);final List<Course> actual = service.findAllCourses();assertEquals(expected, actual);}@Test(expected = PersistenceException.class)public void testFindAllCoursesError() {final CourseRepository repository = Mockito.mock(CourseRepository.class);final Class<Specification<Course>> sClass = null;when(repository.findAll(any(sClass))).thenThrow(new UnitTestException());final CourseFinderService service = new CourseFinderServiceImpl(repository);service.findAllCourses();}@Testpublic void testFindCourseByTestUuid() {final TestRun testRun = new TestRun();final Course course = new Course();final List<Course> expected = Collections.singletonList(course);final CourseRepository repository = Mockito.mock(CourseRepository.class);when(repository.findAll(any(sClass))).thenReturn(expected);final CourseFinderService service = new CourseFinderServiceImpl(repository);final List actual = service.findCoursesByTestRun(testRun);assertEquals(expected, actual);}@Test(expected = PersistenceException.class)public void testFindCourseByTestUuidError() {final TestRun testRun = new TestRun();final CourseRepository repository = Mockito.mock(CourseRepository.class);when(repository.findAll(any(sClass))).thenThrow(new UnitTestException());final CourseFinderService service = new CourseFinderServiceImpl(repository);service.findCoursesByTestRun(testRun);}@Testpublic void testFindCoursesByTestUuid() {final TestRun testRun = new TestRun();final Course course = new Course();final List<Course> expected = Collections.singletonList(course);final CourseRepository repository = Mockito.mock(CourseRepository.class);when(repository.findAll(any(sClass))).thenReturn(expected);final CourseFinderService service = new CourseFinderServiceImpl(repository);final List<Course> actual = service.findCoursesByTestRun(testRun);assertEquals(expected, actual);}@Test(expected = PersistenceException.class)public void testFindCoursesByTestUuidError() {final TestRun testRun = new TestRun();final CourseRepository repository = Mockito.mock(CourseRepository.class);when(repository.findAll(any(sClass))).thenThrow(new UnitTestException());final CourseFinderService service = new CourseFinderServiceImpl(repository);service.findCoursesByTestRun(testRun);}....
}

通过使用@Begin方法,我可以消除很多重复的代码,但是我决定反对它来支持并行测试。

整合测试

我们终于来进行集成测试了。 我们知道我们做对了,因为只有一行可以测试附加功能-计算数据库中的课程数量。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { BusinessApplicationContext.class, TestBusinessApplicationContext.class,TestPersistenceJpaConfig.class })
@Transactional
@TransactionConfiguration(defaultRollback = true)
public class CourseServiceIntegrationTest {@Resourceprivate CourseFinderService fdao;@Resourceprivate CourseManagerService mdao;@Resourceprivate TestRunService testService;@Testpublic void testCourseLifecycle() throws Exception {final TestRun testRun = testService.createTestRun();final String name = "Calculus 101 : " + testRun.getUuid();final Course expected = new Course();expected.setName(name);assertNull(expected.getId());// create courseCourse actual = mdao.createCourseForTesting(name, testRun);expected.setId(actual.getId());expected.setUuid(actual.getUuid());expected.setCreationDate(actual.getCreationDate());assertThat(expected, equalTo(actual));assertNotNull(actual.getUuid());assertNotNull(actual.getCreationDate());// get course by idactual = fdao.findCourseById(expected.getId());assertThat(expected, equalTo(actual));// get course by uuidactual = fdao.findCourseByUuid(expected.getUuid());assertThat(expected, equalTo(actual));// get all coursesfinal List<Course> courses = fdao.findCoursesByTestRun(testRun);assertTrue(courses.contains(actual));// count coursesfinal long count = fdao.countByTestRun(testRun);assertTrue(count > 0);// update courseexpected.setName("Calculus 102 : " + testRun.getUuid());actual = mdao.updateCourse(actual, expected.getName());assertThat(expected, equalTo(actual));// delete Coursemdao.deleteCourse(expected.getUuid(), 0);try {fdao.findCourseByUuid(expected.getUuid());fail("exception expected");} catch (ObjectNotFoundException e) {// expected}testService.deleteTestRun(testRun.getUuid());}
}

源代码

  • 可从http://code.google.com/p/invariant-properties-blog/source/browse/student获取源代码。

参考: 项目学生: Invariant Properties博客上来自JCG合作伙伴 Bear Giles的JPA标准查询 。

翻译自: https://www.javacodegeeks.com/2014/01/project-student-jpa-criteria-queries.html

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

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

相关文章

linux 广播命令,Linux基础命令---ping

pingping指令可以发送ICMP请求到目标地址&#xff0c;如果网络功能正常&#xff0c;目标主机会给出回应信息。ping使用ICMP协议强制发送ECHO_REQUEST报文到目标主机&#xff0c;从主机或网关获取ICMP ECHO_RESPONSE。ECHO_REQUESTt数据报(‘pings’)有一个IP和ICMP报头&#xf…

第5章 Internet协议 [TCP/IP详解 卷1:协议]

IP是TCP/IP协议族中的核心协议。所有TCP、UDP、ICMP和IGMP数据都通过IP数据报传输。IP提供了一种尽力而为、无连接的数据报交付服务。“尽力而为”的含义是不保证IP数据报能成功到达目的地。任何可靠性必须由上层&#xff08;例如TCP&#xff09;提供。IPv4和IPv6都使用这种尽力…

【[SHOI2015]超能粒子炮·改】

就是运用\(Lucas\)推一个柿子 首先是前置芝士\(Lucas\)定理 \[C_{n}^{m}\%pC_{n/p}^{m/p}*C_{n\%p}^{m\%p}\%p\] 至于证明 我建议去问一下Lucas本人 至于这道题&#xff0c;我们要求的是这个柿子 \[\sum_{i0}^kC_{n}^i\%p\] 于是我们设\(f(n,k)\sum_{i0}^kC_{n}^i\) 我们就可以…

Spring REST:异常处理卷。 3

这是该系列中有关Spring REST异常处理的最后一篇文章。 最后&#xff0c;这次我将讨论在表单处理期间可能发生的REST异常的处理。 因此&#xff0c;在本教程中&#xff0c;您将看到与REST&#xff0c;表单和异常处理有关的所有内容。 客户端呢&#xff1f; jQuery将用于反映RES…

centos6安装mysql并远程连接_Ubantu下MySQL安装、部署和远程连接

系统阿里云 ubantu 16.04MySQL 5.0/8.0连接工具 Navicat Premium安装MySQL1、MySQL 5.0直接使用apt命令安装sudo apt install mysql-server输入密码完成安装。安装完mysql-server后&#xff0c;mysql-client就带了&#xff0c;无需单独安装安装成功后输入如下命令检查数据库状态…

linux强制用户改密码,如何在Linux中强制用户在下次登录时更改密码?

由于安全方面的考虑&#xff0c;系统中的用户需要定期更新其密码。在本文中&#xff0c;我们将看到如何强制用户下次登录系统时更改其密码。列出用户首先让我们看一下系统中可用的用户。$ cut -d: -f1 /etc/passwd运行上面的代码给我们以下结果-mailnewsuucpproxywww-databacku…

C# 键盘钩子

C# 键盘钩子 1、键盘钩子&#xff1a; 通过代码将键盘的事件屏蔽掉&#xff0c;达到锁屏的效果。&#xff08;参考地址&#xff1a;https://zhidao.baidu.com/question/135132386108196965.html&#xff09; 2、代码如下&#xff1a; public class Hook : IDisposable{public d…

js中字符串和数组的使用

函数&#xff1a; 函数在调用的时候&#xff0c;会形成一个私有作用域&#xff0c;内部的变量不会被外面访问&#xff0c;这种保护机制叫闭包。这就意味着函数调用完毕&#xff0c;这个函数形成的栈内存会被销毁。 但有时候我们不希望他被销毁。 函数归属谁跟它在哪调用没有关…

Spring REST:异常处理卷。 1个

目录 Spring REST&#xff1a;异常处理卷。 1个 Spring REST&#xff1a;异常处理卷。 2 Spring REST&#xff1a;异常处理卷。 3 大家好&#xff0c;是时候继续在我的博客中发布新文章了。 因此&#xff0c;我很高兴地宣布&#xff0c;我计划编写一系列技术文章。 在当前文…

vue/cli3 配置vux

安装各插件 试过 安装“必须安装”的部分亦可 1、安装vuex npm install vuex --save-dev 2、在项目里面安装vux【必须安装】 npm install vux --save 3、安装vux-loader【必须安装】 npm install vux-loader --save-dev 4、安装less-loader&#xff08;这个是用以正确编译less源…

鼠标右键 移动选定的文件夹到指定位置_怎么把电脑桌面上的文件移动到更加安全的地方...

我们在使用电脑的时候习惯于把各种文档以及其他文件资料随手保存到电脑桌面上&#xff0c;这样操作可以方便以后对这些文档和文件资料的使用、管理&#xff0c;但是由于默认状态下桌面文件位于C盘中&#xff0c;这些文件资料不仅会占用掉C盘的很大的存储空间&#xff0c;并且日…

非常精简的Linux线程池实现(一)——使用互斥锁和条件变量

线程池的含义跟它的名字一样&#xff0c;就是一个由许多线程组成的池子。 有了线程池&#xff0c;在程序中使用多线程变得简单。我们不用再自己去操心线程的创建、撤销、管理问题&#xff0c;有什么要消耗大量CPU时间的任务通通直接扔到线程池里就好了&#xff0c;然后我们的主…

linux vim 执行shell命令行,Linux中vim和shell

在Linux系统中一切皆文件&#xff0c;配置服务其实就是在修改其配置文件的参数&#xff0c;而在日常文件中肯定少不了的就是编辑文档&#xff0c;这就离不开vim&#xff0c;而vim之所以能够得到广大厂商的青睐与用户的认可&#xff0c;原因在于vim编辑器中有三种模式&#xff1…

JS之setTimeOut与clearTimeOut

小练习1&#xff1a;针对HTML&#xff0c;分别使用 setTimeout 和 setInterval 实现以下功能&#xff1a; 点击按钮时&#xff0c;开始改变 fade-obj 的透明度&#xff0c;开始一个淡出&#xff08;逐渐消失&#xff09;动画&#xff0c;直到透明度为0在动画过程中&#xff0c…

运行时的Java 8参数名称

Java 8将引入一种更容易的方法来发现方法和构造函数的参数名称。 在Java 8之前&#xff0c;找到参数名称的方法是在编译阶段打开调试符号&#xff0c;这会在生成的类文件中添加有关参数名称的元信息&#xff0c;然后提取复杂的信息&#xff0c;需要处理字节码。获取参数名称。…

python 可执行文件_如何通过Python函数运行的可执行文件的终端...

我想抑制运行可执行文件的函数产生的所有终端输出. 我试图通过使用每次调用函数时临时重新定义stdout和stderr的上下文管理器来抑制Python函数的输出.这会抑制函数中的print调用产生的终端输出,但是当函数调用产生终端输出的可执行文件时,它似乎不起作用. 那么,如何抑制Python函…

嵌入式linux系统文件,嵌入式Linux文件系统知多少

Nand/Nor Flash在嵌入式Linux产品中&#xff0c;通常使用的存储介质为Nand Flash和Nor Flash&#xff0c;而手机、相机等产品通常使用eMMC、SD Card作为存储介质&#xff0c;导致这种差异的原因主要是成本考量。Nand Flash和Nor Flash具有低成本、高密度存储的优势。但是&#…

三分钟上手Highcharts简易甘特图

根据业务需求&#xff0c;找到了这个很少使用的图形&#xff0c;话不多说&#xff0c;看看该如何使用。首先要引入支持文件&#xff1a;可根据链接下载。 exporting.js&#xff1a;https://img.hcharts.cn/highcharts/modules/exporting.js xrange.js&#xff1a;https://img.h…

WEB语义化

WEB语义化让机器读懂内容&#xff0c;HTML就带有一定「语义」的标签&#xff0c;比如段落&#xff0c;标题&#xff0c;表格和图片等。让机器读懂内容&#xff0c;那么两种方案&#xff1a;第一种让机器变得更人工智能化&#xff0c;也就是现在大火的AI。第二种是人们去发布认可…

Jetty 9.1上的Java WebSockets(JSR-356)

最终发布了Jetty 9.1 &#xff0c;将Java WebSockets&#xff08;JSR-356&#xff09;引入了非EE环境。 这真是个好消息&#xff0c;今天的帖子将介绍如何将这个出色的新API与Spring Framework一起使用。 JSR-356定义了基于注释的简洁模型&#xff0c;以允许现代Java Web应用程…