我原来的问题是https://stackoverflow.com/questions/12172614/hql-join-without-foreign-key-reference 但找不到任何解决方案,因此继续使用 JPA 进行本机查询。 entityManager 的 createNativeQuery 返回 Query 对象,该对象又返回
List<Object[]>
。我不想在迭代列表时处理索引,因为它本质上很容易出错。因此我查看了其他一些解决方案,并发现 JPQL 的构造函数表达式作为解决方案之一。
表结构是
Schema1 -TableA
- NameColumn
- PhoneColumn
对应的Java类是
public class PersonSearch implements Serializable {
public PersonSearch (String NameColumn, String PhoneColumn) {
this.name = NameColumn;
this.phone = PhoneColumn;
}
private String name;
private String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
查询的是
Select NEW com.xyz.PersonSearch(ms.NameColumn, ms.PhoneColumn) From Schema1.TableA ms Where ms.PhoneColumn='9134409930'
使用entityManager API运行此查询时
entityManager.createQuery(queryString, PersonSearch.class);
低于错误。
Caused by: org.hibernate.hql.ast.QuerySyntaxException: Schema1.TableA is not mapped [Select NEW com.xyz.PersonSearch(ms.NameColumn, ms.PhoneColumn) From Schema1.TableA ms Where ms.PHONE='9134409930']
我的代码有什么问题吗?有什么想法吗?
根据《Pro EJB 3 Java Persistence API》一书
构造函数表达式
涉及多个表达式的
子句的更强大形式是构造函数 表达式,它指定查询结果将使用用户指定的存储 对象类型。考虑以下查询:SELECT
SELECT NEW example.EmployeeDetails(e.name, e.salary, e.department.name) FROM Employee e
该查询的结果类型为
类型。作为查询处理器 迭代查询的结果,它使用以下方法实例化example.EmployeeDetails
的新实例 与查询中列出的表达式类型匹配的构造函数。在这种情况下,表达式 类型有 String、Double 和 String,因此查询引擎将搜索具有这些类型的构造函数 参数的类类型。因此,结果查询集合中的每一行都是一个实例EmployeeDetails
包含员工姓名、工资和部门名称。EmployeeDetails
结果对象类型必须使用对象的完全限定名称来引用。这 然而,类不必以任何方式映射到数据库。任何具有构造函数的类 与
子句中列出的表达式兼容,可以在构造函数中使用 表达。SELECT
构造函数表达式是构建粗粒度数据传输的强大工具 对象或视图对象以供其他应用程序层使用。而不是手动构建 对于这些对象,可以使用单个查询将视图对象收集在一起以准备呈现 在网页上。
示例代码如下
List result = em.createQuery("SELECT NEW example.EmpMenu(e.name, e.department.name) " +
"FROM Project p JOIN p.employees e " +
"WHERE p.name = ?1 " +
"ORDER BY e.name").setParameter(1, projectName).getResultList();
EmpMenu 类是一个简单的 pojo,没有注释,但具有正确的构造函数来匹配构造函数表达式。结果是返回的每一行的 EmpMenu 对象列表。
我相信您的 SQL 部分“.... From Schema1.TableA ms ..”应该引用映射的实体。因此,您应该有一个映射到 TableA 的实体,然后 jpql 应该更类似于“.... From MyTableAEntity ms ...”,其中 MyTableAEntity 具有将其映射到 DB 表 TableA 的所有正确的 jpa 注释。正如书中片段所述,“SELECT NEW ...”的目标不必映射,但 FROM 子句中引用的实体必须映射。
要实现此目的,您可以在 JPA 查询中使用 JPQL(Java 持久性查询语言)构造函数表达式。构造函数表达式用于创建自定义结果类的实例。
首先,创建一个自定义类来保存结果信息。在您的情况下,此类可能名为 BookAuthorInfo 并具有接受必要值(作者姓名和书名)的构造函数。
public class BookAuthorInfo {
private String name;
private String title;
public BookAuthorInfo(String name, String title) {
this.name = name;
this.title = title;
}
}
接下来,在 JPQL 查询中使用构造函数表达式从实体中选择所需的属性并构造自定义类的实例。
TypedQuery<BookAuthorInfo> query = entityManager.createQuery(
"SELECT NEW com.example.BookAuthorInfo(a.name, b.title) " +
"FROM Book b JOIN b.author a " +
"WHERE b.publicationYear = :year", BookAuthorInfo.class);
query.setParameter("年份",desiredYear); 列出结果 = query.getResultList();
此方法允许您从多个实体获取特定属性,并使用基于构造函数的 JPA 查询构造自定义结果对象。