JPA:使用 criteriabuilder 查找实体:属性名称与注释不同?
JPA: Using criteriabuilder to find entities: Attribute name different from annotation?
我有一个包含员工信息的 mysql 数据库,每个员工都有一个技术 ID 作为主键。在 MySQL 中选择行匹配条件,我可以使用以下语句(有效)
SELECT * FROM database_test.employee WHERE fist_name='First1';
在 Java 中,我还可以将其用作本机语句来获得我想要的(有效):
List<EmployeeEntity2> objects = m_em.createNativeQuery(
"SELECT * database_test.employee WHERE first_name='First1'",
EmployeeEntity2.class).getResultList();
但是,我想使用 Criteriabuilder 获得相同的结果,然后将其概括为多个 columnName=columnEntry 选择。
public List<EmployeeEntity2> testNoParameter() {
//Based on https://www.objectdb.com/java/jpa/query/criteria
CriteriaBuilder cb = m_em.getCriteriaBuilder();
CriteriaQuery<EmployeeEntity2> q = cb.createQuery(EmployeeEntity2.class);
Root<EmployeeEntity2> c = q.from(EmployeeEntity2.class);
ParameterExpression<String> p = cb.parameter(String.class);
//Works
//q.select(c).where(cb.equal(c.get("firstName"), p));
//Won't work
q.select(c).where(cb.equal(c.get("first_name"), p));
TypedQuery<EmployeeEntity2> query = m_em.createQuery(q);
query.setParameter(p, "First1");
List<EmployeeEntity2> results = query.getResultList();
return results;
}
使用 "fist_name" - 实体中的列名注释 - 将产生以下 java.lang.IllegalArgumentException 其中:
Unable to locate Attribute with the the given name [first_name] on this ManagedType [xx.xxx.database.EmployeeEntity2]
EmployeeEntity2 有 "fist_name" 注释:
@Column(name = "first_name", nullable = false)
@Override
public String getFirstName() {
return super.getFirstName();
}
所以 "first_name" 应该存在,但是(通过一些调试)我发现预期的属性是出于某种原因 "firstName" 而不是 - 我没有 defined/annotated - 所以在哪里它来自 - 我如何使用数据库中实际定义的列名(列 = "first_name")?
您应该使用 属性 实体名称(而不是列名称)在条件生成器中使用它,而不是
q.select(c).where(cb.equal(c.get("first_name"), p));
使用
q.select(c).where(cb.equal(c.get("firstName"), p));
CriteriaBuilder
与 RDBMS 模式无关,因此您使用模型(实体),而不是模式(table 名称等)。
在 JPA 中,您通常不使用 SQL,而是使用 JPQL。在 JPQL 中你的 SQL 相当于
"SELECT e FROM EmployeEntity2 e WHERE e.firstName='First1'"
CriteriaQuery
树和 JPQL
字符串稍后会向下转换为相同的查询树(不记得名字了),因此它们都必须遵守相同的规则。
我有一个包含员工信息的 mysql 数据库,每个员工都有一个技术 ID 作为主键。在 MySQL 中选择行匹配条件,我可以使用以下语句(有效)
SELECT * FROM database_test.employee WHERE fist_name='First1';
在 Java 中,我还可以将其用作本机语句来获得我想要的(有效):
List<EmployeeEntity2> objects = m_em.createNativeQuery(
"SELECT * database_test.employee WHERE first_name='First1'",
EmployeeEntity2.class).getResultList();
但是,我想使用 Criteriabuilder 获得相同的结果,然后将其概括为多个 columnName=columnEntry 选择。
public List<EmployeeEntity2> testNoParameter() {
//Based on https://www.objectdb.com/java/jpa/query/criteria
CriteriaBuilder cb = m_em.getCriteriaBuilder();
CriteriaQuery<EmployeeEntity2> q = cb.createQuery(EmployeeEntity2.class);
Root<EmployeeEntity2> c = q.from(EmployeeEntity2.class);
ParameterExpression<String> p = cb.parameter(String.class);
//Works
//q.select(c).where(cb.equal(c.get("firstName"), p));
//Won't work
q.select(c).where(cb.equal(c.get("first_name"), p));
TypedQuery<EmployeeEntity2> query = m_em.createQuery(q);
query.setParameter(p, "First1");
List<EmployeeEntity2> results = query.getResultList();
return results;
}
使用 "fist_name" - 实体中的列名注释 - 将产生以下 java.lang.IllegalArgumentException 其中:
Unable to locate Attribute with the the given name [first_name] on this ManagedType [xx.xxx.database.EmployeeEntity2]
EmployeeEntity2 有 "fist_name" 注释:
@Column(name = "first_name", nullable = false)
@Override
public String getFirstName() {
return super.getFirstName();
}
所以 "first_name" 应该存在,但是(通过一些调试)我发现预期的属性是出于某种原因 "firstName" 而不是 - 我没有 defined/annotated - 所以在哪里它来自 - 我如何使用数据库中实际定义的列名(列 = "first_name")?
您应该使用 属性 实体名称(而不是列名称)在条件生成器中使用它,而不是
q.select(c).where(cb.equal(c.get("first_name"), p));
使用
q.select(c).where(cb.equal(c.get("firstName"), p));
CriteriaBuilder
与 RDBMS 模式无关,因此您使用模型(实体),而不是模式(table 名称等)。
在 JPA 中,您通常不使用 SQL,而是使用 JPQL。在 JPQL 中你的 SQL 相当于
"SELECT e FROM EmployeEntity2 e WHERE e.firstName='First1'"
CriteriaQuery
树和 JPQL
字符串稍后会向下转换为相同的查询树(不记得名字了),因此它们都必须遵守相同的规则。