我们今天在这里看到的是适用于任何JPA实现的简单解决方案:Hibernate,OpenJPA,EclipseLink等。
这篇文章中找到的基本源代码来自于本书:“ Pro JPA 2:掌握Java™持久性API – Mike Keith,Merrick Schincariol ”。 这篇文章将添加到原始代码中:查询参数和NamedQuery测试。
模型类和数据生成
下面是模型类的代码:
package com.model;
import java.util.*;
import javax.persistence.*;
@Entity
@NamedQueries({
@NamedQuery(name="Person.findByName", query="select p from Person p where p.name = :name"),
@NamedQuery(name="Person.findByAge", query="select p from Person p where p.age = :age", hints={@QueryHint(name="org.hibernate.timeout", value="1000")})
})
public class Person {
public static final String FIND_BY_NAME = "Person.findByName";
public static final String FIND_BY_AGE = "Person.findByAge";
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private int age;
public Person() {
}
public Person(int id) {
this.id = id;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
private List<Dog> dogs;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="address_id")
private Address address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<Dog> getDogs() {
if (dogs == null) {
dogs = new ArrayList<Dog>();
}
return dogs;
}
public void setDogs(List<Dog> dogs) {
this.dogs = dogs;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public int hashCode() {
return getId();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Person) {
Person person = (Person) obj;
return person.getId() == getId();
}
return false;
}
@Override
public String toString() {
return "Person name: " + name;
}
}
package com.model;
import java.util.Date;
import javax.persistence.*;
@Entity
@NamedQueries(value={@NamedQuery(name="Dog.FindByDateOfBirth", query="select d from Dog d where d.dateOfBirth = :dateOfBirth"),
@NamedQuery(name="Dog.FindByPerson", query="select d from Dog d where d.person = :personObject")})
public class Dog {
public static final String FIND_BY_DATE_OF_BIRTH = "Dog.FindByDateOfBirth";
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private double weight;
@Temporal(TemporalType.TIMESTAMP)
private Date dateOfBirth;
public Dog() {
}
public Dog(String name, double weight, Date dateOfBirth) {
this.name = name;
this.weight = weight;
this.dateOfBirth = dateOfBirth;
}
public static void main(String[] args) {
System.out.println(new Date());
}
@ManyToOne
private Person person;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public Date getDateOfBirth() {
return dateOfBirth;
}
public void setDateOfBirth(Date dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@Override
public int hashCode() {
return getId();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Dog) {
Dog dog = (Dog) obj;
return dog.getId() == getId();
}
return false;
}
@Override
public String toString() {
return "Dog name: " + name;
}
}
package com.model;
import javax.persistence.*;
@Entity
@NamedQuery(name="Address.FindAll", query="select a from Address a")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String streetName;
private int houseNumber;
public Address() {
}
public Address(String streetName, int houseNumber) {
this.streetName = streetName;
this.houseNumber = houseNumber;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
public int getHouseNumber() {
return houseNumber;
}
public void setHouseNumber(int houseNumber) {
this.houseNumber = houseNumber;
}
@Override
public int hashCode() {
return getId();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Address) {
Address address = (Address) obj;
return address.getId() == getId();
}
return false;
}
@Override
public String toString() {
return "Adress street name: " + streetName;
}
}
在上面的代码中,我们获得了几个JPA关系作为示例。
贝娄(Bellow)是将处理事务和将写入HSQLDB数据库的数据的类:
package com.main;
import java.text.*;
import java.util.Date;
import javax.persistence.*;
import com.model.*;
public class CodeGenerator {
private static EntityManagerFactory emf;
private static EntityManager em;
public static final String PERSON01_NAME = "John";
public static final String PERSON02_NAME = "Mary";
public static final String PERSON03_NAME = "Anna";
public static final String PERSON04_NAME = "Joseph";
public static final String PERSON05_NAME = "Mark";
public static final String PERSON06_NAME = "I will not have any relationship";
public static void startConnection() {
emf = Persistence.createEntityManagerFactory("QueryTester");
em = emf.createEntityManager();
em.getTransaction().begin();
}
public static void closeConnection() {
em.getTransaction().commit();
emf.close();
}
public static void generateData() {
int year = 1995;
int month = 1;
int day = 10;
Dog dog01 = new Dog("Yellow", 3.5d, createNewDate(day, month, year));
Dog dog02 = new Dog("Brown", 8.5d, createNewDate(++day, ++month, ++year));
Dog dog03 = new Dog("Dark", 15.5d, createNewDate(++day, ++month, ++year));
Dog dog04 = new Dog("Kaka", 4.3d, createNewDate(++day, ++month, ++year));
Dog dog05 = new Dog("Pepe", 8.2d, createNewDate(++day, ++month, ++year));
Dog dog06 = new Dog("Casillas", 6.1d, createNewDate(++day, ++month, ++year));
Dog dog07 = new Dog("Fish", 6.7d, createNewDate(++day, ++month, ++year));
Dog dog08 = new Dog("Lion", 3.1d, createNewDate(++day, ++month, ++year));
Dog dog09 = new Dog("Cat", 5.5d, createNewDate(++day, ++month, ++year));
Dog dog10 = new Dog("Java", 21.7d, createNewDate(++day, ++month, ++year));
Dog dog11 = new Dog("JSF", 23.65d, createNewDate(++day, ++month, ++year));
Dog dog12 = new Dog("VRaptor", 24.0d, createNewDate(++day, ++month, ++year));
Dog dog13 = new Dog("Ferrari", 3.7d, createNewDate(++day, ++month, ++year));
Dog dog14 = new Dog("Porshe", 1.33d, createNewDate(++day, ++month, ++year));
Dog dog15 = new Dog("Bike", 4.44d, createNewDate(++day, ++month, ++year));
Dog dog16 = new Dog("Rambo", 5.44d, createNewDate(++day, ++month, 2015));
Dog dog17 = new Dog("Terminator", 3.88d, createNewDate(++day, ++month, 2016));
Dog dog18 = new Dog("John McClan", 3.88d, createNewDate(++day, ++month, 2016));
Person person01 = new Person(PERSON01_NAME, 33);
person01.getDogs().add(dog01);
person01.getDogs().add(dog02);
person01.getDogs().add(dog03);
person01.setAddress(new Address("Street A", 30));
dog01.setPerson(person01);
dog02.setPerson(person01);
dog03.setPerson(person01);
Person person02 = new Person(PERSON02_NAME, 27);
person02.getDogs().add(dog04);
person02.getDogs().add(dog05);
person02.getDogs().add(dog06);
person02.setAddress(new Address("Street B", 60));
dog04.setPerson(person02);
dog05.setPerson(person02);
dog06.setPerson(person02);
Person person03 = new Person(PERSON03_NAME, 7);
person03.getDogs().add(dog07);
person03.getDogs().add(dog08);
person03.getDogs().add(dog09);
person03.setAddress(new Address("Street B", 90));
dog07.setPerson(person03);
dog08.setPerson(person03);
dog09.setPerson(person03);
Person person04 = new Person(PERSON04_NAME, 43);
person04.getDogs().add(dog10);
person04.getDogs().add(dog11);
person04.getDogs().add(dog12);
person04.setAddress(new Address("Street C", 120));
dog10.setPerson(person04);
dog11.setPerson(person04);
dog12.setPerson(person04);
Person person05 = new Person(PERSON05_NAME, 70);
person05.getDogs().add(dog13);
person05.getDogs().add(dog14);
person05.getDogs().add(dog15);
person05.getDogs().add(dog16);
person05.setAddress(new Address("Street D", 150));
dog13.setPerson(person05);
dog14.setPerson(person05);
dog15.setPerson(person05);
dog16.setPerson(person05);
Person person06 = new Person(PERSON06_NAME, 45);
em.persist(person01);
em.persist(person02);
em.persist(person03);
em.persist(person04);
em.persist(person05);
em.persist(person06);
em.persist(dog17);
em.persist(dog18);
em.flush();
}
private static Date createNewDate(int day, int month, int year) {
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
try {
return formatter.parse("" + day + "/" + month + "/" + year);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
public static EntityManager getEntityManager() {
return em;
}
}
可以在以下代码的“ src / META-INF”文件夹中找到“ persistence.xml”文件:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="QueryTester"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:." />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.connection.shutdown" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="false"/>
</properties>
</persistence-unit>
</persistence>
抽象测试班
package com.main;
import javax.persistence.Query;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.model.Person;
/**
* @author Pro JPA 2 book
* @Empowered by uaiHebert
*
*/
public abstract class AbstractQueryTester {
protected static void populateParameters(Query query, String parameters) {
for (String parameter : parameters.split(";")) {
String parameterKey = parameter.split("-")[0];
String parameterValue = parameter.split("-")[1];
String parameterType = parameter.split("-")[2];
query.setParameter(parameterKey, configureParameterValue(parameterValue, parameterType));
}
}
private static Object configureParameterValue(String parameterValue, String parameterType) {
if (parameterType.equalsIgnoreCase("integer")) {
try {
return Integer.parseInt(parameterValue);
} catch (Exception e) {
throw new IllegalArgumentException("Invalid parameter value as number: " + parameterValue);
}
}
if (parameterType.equalsIgnoreCase("string")) {
return parameterValue;
}
if (parameterType.equalsIgnoreCase("person")) {
int personId;
try {
personId = Integer.valueOf(parameterValue);
} catch (Exception e) {
throw new IllegalArgumentException("Invalid parameter value as number: " + parameterValue);
}
return new Person(personId);
}
throw new IllegalArgumentException("Invalid parameter type: " + parameterType);
}
protected static void printResult(Object result) throws Exception {
if (result == null) {
System.out.print("NULL");
} else if (result instanceof Object[]) {
Object[] row = (Object[]) result;
System.out.print("[");
for (int i = 0; i < row.length; i++) {
printResult(row[i]);
}
System.out.print("]");
} else if (result instanceof Long || result instanceof Double || result instanceof String) {
System.out.print(result.getClass().getName() + ": " + result);
} else {
System.out.print(ReflectionToStringBuilder.toString(result, ToStringStyle.SHORT_PREFIX_STYLE));
}
System.out.println();
}
}
关于上面的代码:
- populateParameters方法将自动填充所有查询参数。 如果需要,Eclipse控制台将要求开发人员键入查询信息和查询参数。 查询参数应遵循以下语法要求:
- 0个参数:只需按“ Enter”
- configureParameterValue方法会将参数值“广播”为查询所需的正确类型。 它允许原始值和类。
- printResult方法将显示查询结果。
动态查询测试
package com.main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
/**
* @author Pro JPA 2 book
* @Empowered by uaiHebert
*
*/
public class DynamicQueryTester extends AbstractQueryTester {
public static void main(String[] args) throws IOException {
CodeGenerator.startConnection();
CodeGenerator.generateData();
EntityManager em = CodeGenerator.getEntityManager();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
System.out.print("Type your JPQL and press Enter > ");
String dynamicQuery = reader.readLine();
if (dynamicQuery.equals("quit")) {
break;
}
if (dynamicQuery.length() == 0) {
continue;
}
System.out.println("Type the namedQuery parameters.");
System.out.println("All paramters should be like: id-2-integer;name-John-string");
System.out.println("Or just press enter for 0 parameters");
String parameters = reader.readLine();
try {
Query query = em.createQuery(dynamicQuery);
if (parameters.length() > 0) {
populateParameters(query, parameters);
}
@SuppressWarnings("rawtypes")
List result = query.getResultList();
if (result.size() > 0) {
int count = 0;
for (Object o : result) {
System.out.print(++count + " ");
printResult(o);
}
} else {
System.out.println("0 results returned");
}
} catch (Exception e) {
e.printStackTrace();
}
}
CodeGenerator.closeConnection();
}
}
上面的代码将启动一个事务,在运行时内存中创建数据库数据,并允许开发人员测试任何类型的动态查询。 要测试JPQL / HQL,开发人员只需在控制台中键入查询代码。
要结束循环,请不要键入任何查询数据,只需键入“ quit”并按“ Enter”即可。
NamedQuery测试
package com.main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
/**
* @author Pro JPA 2 book
* @Empowered by uaiHebert
*
*/
public class NamedQueryTester extends AbstractQueryTester {
public static void main(String[] args) throws IOException {
CodeGenerator.startConnection();
CodeGenerator.generateData();
EntityManager em = CodeGenerator.getEntityManager();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
System.out.print("Type the NamedQuery name > ");
String namedQueryName = reader.readLine();
if (namedQueryName.equals("quit")) {
break;
}
if (namedQueryName.length() == 0) {
continue;
}
System.out.println("Type the namedQuery parameters.");
System.out.println("Press enter for 0 parameters");
System.out.println("Or type all paramters like: id-2,name-4");
String parameters = reader.readLine();
try {
Query query = em.createNamedQuery(namedQueryName);
if (parameters.length() > 0) {
populateParameters(query, parameters);
}
@SuppressWarnings("rawtypes")
List result = query.getResultList();
if (result.size() > 0) {
int count = 0;
for (Object o : result) {
System.out.print(++count + " ");
printResult(o);
}
} else {
System.out.println("0 results returned");
}
} catch (Exception e) {
System.err.println(e.getClass() + e.getMessage());
}
}
CodeGenerator.closeConnection();
}
}
上面的代码将启动一个事务,在运行时内存中创建数据库数据,并允许测试在模型类中配置的NamedQueries。 要测试NamedQueries,只需在控制台中键入其名称。
要结束循环,请不要键入任何NamedQuery名称,只需键入“ quit”并按“ Enter”即可。
运行应用程序
运行类DynamicQueryTester,然后在控制台中键入以下文本:“ 从Person p中选择p ”。 按Enter键两次,以下文本将出现在控制台中:
在第一个“ Enter”键上,将显示一条消息,询问是否有参数。
在控制台中键入:“ 从Person p中选择p,其中p.age>:age ”,然后按“ Enter”。 输入参数:“ age-69-integer ”。 按回车,将显示以下结果:
要完成正在运行的代码,请输入单词“ quit”,然后按“ Enter”按钮。
现在运行类NamedQueryTester的代码。
在控制台中键入NamedQuery名称“ Dog.FindByPerson”,然后按Enter。 输入“ personObject-1-person”参数,将显示以下结果:
将此邮政编码与您的应用程序代码一起使用
您可以通过两种方式使用本文的代码:将应用程序模型类添加到本文的项目中,或在应用程序中使用该项目的主包中的代码。
将您的模型类添加到这篇文章的项目中 :
- 将模型类复制到“ com.model”包中。
- 设置persistence.xml以访问数据库
使用应用程序主包中的代码 :
- 设置在CodeGenerator类中找到的PersistenceUnit。
- 使用在libs文件夹中找到的Apache库:“ commons-lang3-3-1.jar ”。
对于这两种方法,都需要以下步骤:
- 编辑方法“ AbstractQueryTester.configureParameterValue ”以接受将与查询一起使用的所有属性值/类型/类。
- 将“ hibernate.hbm2ddl.auto ”配置编辑为“ none”或“ validate”。 该配置位于“ persistence.xml ”文件中。
- 仅在CodeGenerator类中调用方法以启动/关闭连接。
提案
在下面,您会发现一些与此代码有关的建议:
- 使用反射技术在“ AbstractQueryTester.configureParameterValue ”方法中创建类。
- 提交后,应用Jenkins验证某些JPQL是否具有正确的语法。
结束
希望这篇文章对您有所帮助。
如果您有任何疑问/建议,请将其发布。
参考:在uaiHebert博客上, 如何从我们的JCG合作伙伴 Hebert Coelho进行部署而无需部署即可测试JPQL / HQL 。
翻译自: https://www.javacodegeeks.com/2012/07/test-jpql-hql-without-deploy.html