编译时检查JPA查询

JPA提供了几种查询数据的方法。 可以根据各种标准(例如,所使用的语言(SQL与JPQL)或查询是静态的(编译时间)还是动态的(执行时间))对此类替代方案进行分类。

静态查询是使用@Entity类定义本身中的注释@NamedQuery ( javax.persistence.NamedQuery )和@NamedQueries ( javax.persistence.NamedQueries )定义的:

@NamedQuery(name="findAllCustomersWithName",query="SELECT c FROM Customer c WHERE c.name LIKE :custName")

另一方面, EntityManager提供的方法createQuery(…)createNativeQuery(…)分别采用JPQL或SQL查询。

因此,可以在编译或执行时定义查询。

注意 :建议始终使用Query中的 setParameter(…)方法使用参数化查询,以避免SQL注入漏洞。)

标准API

但是,JPA提供了另一种查询对象的方法: Criteria API 。 确实,切换到JPA的动机之一是处理对象而不是SQL方言,不是吗?

让我们看一个示例代码。

实体定义:

@Entity
public class User {@Idprivate Integer userId;@Basic@Column(length=15, nullable=false)private String name;@Basic@Column(length=64, nullable=false)private String userDigestedPasswd;@Basic@Column(length=50, nullable=true)private String email;@Basic@Column(nullable=false)public Integer privilegeLevel;@Basic@Column(nullable=false)private Boolean active;
}

让我们查询数据库并检查结果(使用JUnit):

public class UserTest {@Testpublic void testUserCriteria(){
EntityManagerFactory emf = null;
EntityManager em = null;
try {emf = Persistence.createEntityManagerFactory("criteria");em = emf.createEntityManager();final CriteriaBuilder cb = em.getCriteriaBuilder();final CriteriaQuery<User> q = cb.createQuery(User.class);final Root<User> users = q.from(User.class);final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);q.select(users).where(condition).orderBy(cb.asc(users.get("userId")));em.getTransaction().begin();List<User> result = em.createQuery(q).getResultList();em.getTransaction().commit();assertNotNull(result);assertEquals(2, result.size());assertEquals(1, (int)result.get(0).getUserId());assertEquals("Pepe", result.get(0).getName());assertEquals(3, (int)result.get(1).getUserId());assertEquals("Dolores", result.get(1).getName());} catch (Exception e) {fail("Unexpected Exception " + e.getMessage());
} finally {if (em != null)em.close();if (emf != null)emf.close();
}
}
}

以下几行显示查询的创建:

final CriteriaBuilder cb = em.getCriteriaBuilder();final CriteriaQuery<User> q = cb.createQuery(User.class);final Root<User> users = q.from(User.class);final Predicate condition = cb.equal(users.get("privilegeLevel);q.select(users).where(condition).orderBy(cb.asc(users.get("userId

首先,从EntityManager获得CriteriaBuilder 。 然后,获取一个CriteriaQuery实例,将该类设置为保存结果。 在我们的例子中, User.class

final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<User> q = cb.createQuery(User.class);

接下来,必须设置要对其运行查询的实体:

final Root<User> users = q.from(User.class);

现在是时候设置查询匹配条件了。 在示例代码中,条件只是属性privilegeLevel等于5:

final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);

最后,构建查询以在Root上添加条件。 也可以设置分组和排序选项(即,对userId设置升序排序):

q.select(users).where(condition).orderBy(cb.asc(users.get(“userId”)));

请查看CriteriaBuilder中的不同选项。 可以在CriteriaQuery中找到分组和排序选项。

使用元模型进行编译时检查

请注意,我们刚刚构建的查询需要跟踪对象属性名称。 例如,要构建查询,请使用属性privilegeLevel的名称。 但是,如果稍后更改属性名称,则代码将编译并且仅在运行时失败:

final CriteriaQuery<User> q = cb.createQuery(User.class);final Root<User> users = q.from(User.class);final Predicate condition = cb.equal(users.get("privilegeLevel"), 5);q.select(users).where(condition).orderBy(cb.asc(users.get("userId")));

那不好

幸运的是,使用元模型,我们将能够构建编译时检查的查询。 可以在The Java EE6 Tutorial中找到简短的介绍。

使用元模型,代码将引用对象的SingularAttribute,而不是使用包含对象属性名称的String。 因此,如果稍后更改对象属性,则编译器将为我们标记该属性。

首先,必须创建对应的元模型类( EntityType )。 尽管可以通过多种方法实现,但对于openJPA实现,最简单的方法可能是添加openJPA构建标志 : -Aopenjpa.metamodel = true

因此,我们创建了User_类,它是User的对应元模型类:

* Generated by OpenJPA MetaModel Generator Tool. **/
package com.wordpress.tododev.criteria.entities;
import javax.persistence.metamodel.SingularAttribute;
@javax.persistence.metamodel.StaticMetamodel
(value=com.wordpress.tododev.criteria.entities.User.class)
@javax.annotation.Generated
(value="org.apache.openjpa.persistence.meta.AnnotationProcessor6",date="Mon Mar 04 16:47:46 CET 2013")
public class User_ {public static volatile SingularAttribute<User,Boolean> active;public static volatile SingularAttribute<User,String> email;public static volatile SingularAttribute<User,String> name;public static volatile SingularAttribute<User,Integer> privilegeLevel;public static volatile SingularAttribute<User,String> userDigestedPasswd;public static volatile SingularAttribute<User,Integer> userId;
}

如果将此类添加到代码库中,则以后对User类的任何更改都不会引起注意。 而且,将自动生成的项目添加到代码版本控制系统中不是一个好主意。

使用antmaven或类似工具,可以添加目标以创建元模型类。 在更改JPA实体后,应执行该目标。

也可以使用IDE。 例如,对于使用Eclipse的,只需要已经提到编译标志添加属性- > Java的反编译>注解处理器和的lib(JAR)包含所选择的JPA实现第厂路注释处理器的注释处理器(可能导致自动模式下的编译问题,前提是必须在使用它的代码之前编译元模型类)。

让我们向套件添加另一个测试。 这个不会提供包含属性名称的String,而是使用metamodel类:

@Testpublic void testUserCriteriaMetaModel(){EntityManagerFactory emf = null;EntityManager em = null;try {emf = Persistence.createEntityManagerFactory("criteria");em = emf.createEntityManager();final CriteriaBuilder cb = em.getCriteriaBuilder();final CriteriaQuery<User> q = cb.createQuery(User.class);final Metamodel m = em.getMetamodel();final Root<User> user = q.from(m.entity(User.class));final Predicate condition = cb.equal(user.get(User_.privilegeLevel), 5);q.select(user).where(condition).orderBy(cb.asc(user.get(User_.userId)));em.getTransaction().begin();List<User> result = em.createQuery(q).getResultList();em.getTransaction().commit();assertNotNull(result);assertEquals(2, result.size());assertEquals(1, (int)result.get(0).getUserId());assertEquals("Pepe", result.get(0).getName());assertEquals(3, (int)result.get(1).getUserId());assertEquals("Dolores", result.get(1).getName());
} catch (Exception e) {fail("Unexpected Exception " + e.getMessage());} finally {if (em != null)em.close();if (emf != null)emf.close();}}

更相关的更改是user.get(User_.privilegeLevel)而不是users.get(“ privilegeLevel”)  user.get(User_.userId)而不是   users.get(“ userId”)。

  • 从GitHub下载源代码。

翻译自: https://www.javacodegeeks.com/2014/08/compile-time-checking-jpa-queries.html

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

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

相关文章

深入理解DOM节点关系

前面的话 DOM可以将任何HTML描绘成一个由多层节点构成的结构。节点分为12种不同类型&#xff0c;每种类型分别表示文档中不同的信息及标记。每个节点都拥有各自的特点、数据和方法&#xff0c;也与其他节点存在某种关系。节点之间的关系构成了层次&#xff0c;而所有页面标记则…

Windows服务编写

摘要&#xff1a;几乎所有的操作系统在启动的时候都会启动一些不需要与用户交互的进程&#xff0c;这些进程在Windows中就被称作服务。它由服务程序、服务控制程序&#xff08;&#xff33;&#xff23;&#xff30;&#xff0c;service control program&#xff09;和服务控制…

1031 查验身份证 (15 分)

#include <iostream> #include <string> using namespace std; int main() {int n, i, sum 0, cnt 0; // 这是为零很重要string s;int w[17] { 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 };char z[11] { 1, 0, X, 9, 8, 7, 6, 5, 4, 3, 2 };cin >> n;getcha…

分布式锁(基于redis和zookeeper)详解

分布式锁&#xff08;基于redis和zookeeper&#xff09;详解 https://blog.csdn.net/a15835774652/article/details/81775044 为什么写这篇文章&#xff1f; 目前网上大部分的基于zookeeper&#xff0c;和redis的分布式锁的文章都不够全面。要么就是特意避开集群的情况&#xf…

深入理解this机制系列第三篇——箭头函数

前面的话 this机制与函数调用有关&#xff0c;而作用域则与函数定义有关。有没有什么是可以将this机制和作用域联系起来的呢&#xff1f;本文将介绍ES6新增的内容——箭头函数 痛点 对于闭包的痛点在于&#xff0c;闭包的this默认绑定到window对象&#xff0c;但又常常需要访问…

C# CheckedListBox控件的用法

最近用到checklistbox控件&#xff0c;在使用其过程中&#xff0c;花了较多的时间&#xff0c;这里我收集了其相关的代码段&#xff0c;希望对大家有所帮助。1.添加项checkedListBox1.Items.Add("蓝色"); checkedListBox1.Items.Add("红色"); checkedListB…

如何从JSF获取JSON响应?

许多JavaScript小部件都希望使用JSON格式的数据和选项。 如今&#xff0c;选择一个很酷的小部件并将其包装在一个复合组件中确实很容易。 但是第一个问题是如何发送AJAX请求并以正确的JSON格式接收响应。 JSF用户经常会提出这个问题 。 您需要的只是一个XHTML facelet&#xff…

使用AtomicLong,经典银行账户问题

1.新建Account类&#xff0c;使用AtomicLong定义账户余额&#xff0c;增加和减少金额方法使用getAndAdd方法。 package com.xkzhangsan.atomicpack.bank;import java.util.concurrent.atomic.AtomicLong;public class Account {private AtomicLong balance new AtomicLong();p…

Redis与Zookeeper实现分布式锁的区别

Redis与Zookeeper实现分布式锁的区别 1.分布式锁解决方案 1.采用数据库 不建议 性能不好 jdbc 2.基于Redis实现分布式锁&#xff08;setnx&#xff09;setnx也可以存入key&#xff0c;如果存入key成功返回1&#xff0c;如果存入的key已经存在了&#xff0c;返回0. 3.基于Zookee…

JavaFX技巧12:在CSS中定义图标

当您是像我这样来自Swing的UI开发人员时&#xff0c;您很有可能仍在代码中直接设置图像/图标。 最可能是这样的&#xff1a; import javafx.scene.control.Label; import javafx.scene.image.ImageView;public class MyLabel extends Label {public MyLabel() {setGraphic(new…

被嫌弃的eval和with

前面的话 eval和with经常被嫌弃&#xff0c;好像它们的存在就是错误。在CSS中&#xff0c;表格被嫌弃&#xff0c;在网页中只是用表格来展示数据&#xff0c;而不是做布局&#xff0c;都可能被斥为不规范&#xff0c;矫枉过正。那关于eval和with到底是什么情况呢&#xff1f;本…

短信猫常用AT指令

AT指令短信猫通讯中起着重要的作用&#xff0c;能够通过AT指令控制手机的许多行为&#xff0c;包括拨叫号码、按键控制、传真、GPRS等。AT指令基本用法&#xff1a;1. 测试命令(Test Command)在AT指令后面加上“?”即构成测试命令。例如“ATCSCS?”会列举出所有支持的字符集。…

第八次点评

本周心得&#xff1a; 本周没有作业 &#xff0c;批改的上周的作业。需求分析以及团队的明确分工是开发前准备的要素。本次批改主要侧重于需求分析的调研。 博客园地址https://www.cnblogs.com/zhaojh123/ 博客园点评博客&#xff1a; https://www.cnblogs.com/yanqignkui-123/…

JDBC、Tomcat为什么要破坏双亲委派模型?

问题一&#xff1a;双亲委派模型是什么 如果一个类加载器收到了加载某个类的请求&#xff0c;则该类加载器并不会去加载该类&#xff0c;而是把这个请求委派给父类加载器&#xff0c;每一个层次的类加载器都是如此&#xff0c;因此所有的类加载请求最终都会传送到顶端的启动类加…

JavaFX技巧8:美丽深层

如果要为JavaFX开发UI框架&#xff0c;请养成一种习惯&#xff0c;始终将自定义控件拆分为控件类和外观类。 来自Swing自己&#xff0c;这对我来说并不明显。 Swing还使用MVC概念并将实际的组件呈现委托给UI委托&#xff0c;但是扩展Swing的人们大多将其控件之一子类化&#xf…

dpdk之路-环境部署

dpdk实验环境部署 1、实验环境说明 vmware workstatioin 12 centos 7.5.1804 dpdk-stable-18.11.1 2、实验步骤 &#xff08;1&#xff09;虚拟机安装 http://vault.centos.org/7.5.1804/isos/x86_64/从链接下载CentOS-7-x86_64-DVD-1804.iso&#xff0c;安装时需要准备3张虚拟…

管理好我的业务人员

我所在的一家公司属于一家典型的以业务员为主的公司&#xff0c;没有业务员就无法生存下去的这样一家公司。但在平时的一些管理方面我经常会发现以下几点问题&#xff1a;1. 某些业务人员有时候认为天高皇帝远&#xff0c;我在外面工作&#xff0c;公司不可能派人跟踪管理的。2…

initial、inherit、unset、revert和all

前面的话 在CSS中&#xff0c;有4个关键字理论上可以应用于任何的CSS属性&#xff0c;它们是initial(初始)、inherit(继承)、unset(未设置)、revert(还原)。而all的取值只能是以上这4个关键字。本文将介绍initial、inherit、unset、revert和all initial 表示元素属性的初始默认…

基于知识图谱的医疗诊断系统论文

本作品禁止任何人/企业申请专利&#xff0c;禁止任何人使用本作品参加任何比赛或作为毕业设计&#xff0c;如使用本作品源码进行商业用途务必联系作者。 一.科学性 1.研究意义 信息科技经过 60 余年的发展&#xff0c;已经普及到社会生活的每一个角落。随着信息技术在国家治理、…

SpringBoot:SpringBoot简介

SpringBoot ...如今&#xff0c;有关SpringBoot的话题很多。 那么&#xff0c;SpringBoot是什么&#xff1f; SpringBoot是一个新的Spring产品组合项目&#xff0c;它通过大幅度减少所需的配置量来构建可立即投入生产的Spring应用程序。 Spring Boot通过基于运行时可用的类路径…