JPQL 在 select 语句中包含 elementCollection 映射
JPQL include elementCollection map in select statement
我有一个具有多个属性的@Entity class 公司,在我的数据库中引用了一家公司Table。其中之一表示一个 Map companyProperties,其中公司 table 由 company_properties table 扩展,属性以键值格式保存。
@Entity
@Table(name = "companies")
public class Company extends AbstractEntity {
private static final String TABLE_NAME = "companies";
@Id
@GeneratedValue(generator = TABLE_NAME + SEQUENCE_SUFFIX)
@SequenceGenerator(name = TABLE_NAME + SEQUENCE_SUFFIX, sequenceName = TABLE_NAME + SEQUENCE_SUFFIX, allocationSize = SEQUENCE_ALLOCATION_SIZE)
private Long id;
//some attributes
@ElementCollection
@CollectionTable(name = "company_properties", joinColumns = @JoinColumn(name = "companyid"))
@MapKeyColumn(name = "propname")
@Column(name = "propvalue")
private Map<String, String> companyProperties;
//getters and setters
}
实体管理器能够正确执行查找子句
Company company = entityManager.find(Company.class, companyId);
但是,我无法在此实体中执行 JPQL 查询并相应地检索地图。由于对象很大,我只需要select我实体中的一些属性class。我也不想按 companyProperties 进行过滤,而是要检索所有带有正确分配的 companyid 外键的属性。我尝试做的是以下内容:
TypedQuery<Company> query = entityManager.createQuery("SELECT c.id, c.name, c.companyProperties " +
"FROM Company as c where c.id = :id", Company.class);
query.setParameter("id", companyId);
Company result = query.getSingleResult();
我得到的错误是:
java.lang.IllegalArgumentException: 在 EntityManager 中创建查询时发生异常:
异常描述:编译 [SELECT c.id、c.name、c.companyProperties FROM Company as c where c.id = :id] 时出现问题。 [21, 40] 状态字段路径 'c.companyProperties' 无法解析为集合类型。
org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1616)
org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1636)
com.sun.enterprise.container.common.impl.EntityManagerWrapper.createQuery(EntityManagerWrapper.java:476)
尝试用连接来完成(我得到的最远点是用
Query query = entityManager.createQuery("SELECT c.id, c.name, p " +
"FROM Company c LEFT JOIN c.companyProperties p where c.id = :id");
没有给我正确的结果(它只是 returns 属性 的值,而不是它们的键值列表)。
如何定义正确的查询来执行此操作?
我不喜欢你的 JPA 语法。在您的第一个查询中,您 selecting 了 Company
实体中的各个字段。但这不是 JPA 的工作方式;当您查询时,您会取回整个对象,您可以使用它访问您想要的任何字段。我建议改用以下代码:
TypedQuery<Company> query = entityManager.createQuery("from Company as c where c.id = :id", Company.class);
query.setParameter("id", companyId);
Company result = query.getSingleResult();
同样,对于第二个连接查询,我建议使用以下代码:
Query query = entityManager.createQuery("SELECT c" +
"FROM Company c LEFT JOIN c.companyProperties p WHERE c.id = :id");
query.setParameter("id", companyId);
List<Company> companies = query.getResultList();
只有 select 一个 Company
而不是 属性 实体的原因是属性将作为集合出现在 Company
class 中。假设公司和属性之间存在一对多,您可以从每个 Company
实体访问属性。
您希望在仅对特定字段执行 select 时获得完整的 Company
对象,这是不可能的。如果你真的想节省一些内存(在大多数情况下不会那么成功)并且 select 只是一些字段,那么你应该期待一个 List<Object[]>
:
List<Object[]> results = entityManager.createQuery("SELECT c.id, c.name, p " +
"FROM Company c LEFT JOIN c.companyProperties p where c.id = :id")
.setParameter("id", companyId)
.getResultList();
此处 results
将包含 selected 字段的单个数组。您可以使用 getSingleResult
,但请注意,如果未找到任何结果,它将抛出异常。
我有一个具有多个属性的@Entity class 公司,在我的数据库中引用了一家公司Table。其中之一表示一个 Map companyProperties,其中公司 table 由 company_properties table 扩展,属性以键值格式保存。
@Entity
@Table(name = "companies")
public class Company extends AbstractEntity {
private static final String TABLE_NAME = "companies";
@Id
@GeneratedValue(generator = TABLE_NAME + SEQUENCE_SUFFIX)
@SequenceGenerator(name = TABLE_NAME + SEQUENCE_SUFFIX, sequenceName = TABLE_NAME + SEQUENCE_SUFFIX, allocationSize = SEQUENCE_ALLOCATION_SIZE)
private Long id;
//some attributes
@ElementCollection
@CollectionTable(name = "company_properties", joinColumns = @JoinColumn(name = "companyid"))
@MapKeyColumn(name = "propname")
@Column(name = "propvalue")
private Map<String, String> companyProperties;
//getters and setters
}
实体管理器能够正确执行查找子句
Company company = entityManager.find(Company.class, companyId);
但是,我无法在此实体中执行 JPQL 查询并相应地检索地图。由于对象很大,我只需要select我实体中的一些属性class。我也不想按 companyProperties 进行过滤,而是要检索所有带有正确分配的 companyid 外键的属性。我尝试做的是以下内容:
TypedQuery<Company> query = entityManager.createQuery("SELECT c.id, c.name, c.companyProperties " +
"FROM Company as c where c.id = :id", Company.class);
query.setParameter("id", companyId);
Company result = query.getSingleResult();
我得到的错误是:
java.lang.IllegalArgumentException: 在 EntityManager 中创建查询时发生异常: 异常描述:编译 [SELECT c.id、c.name、c.companyProperties FROM Company as c where c.id = :id] 时出现问题。 [21, 40] 状态字段路径 'c.companyProperties' 无法解析为集合类型。 org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1616) org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1636) com.sun.enterprise.container.common.impl.EntityManagerWrapper.createQuery(EntityManagerWrapper.java:476)
尝试用连接来完成(我得到的最远点是用
Query query = entityManager.createQuery("SELECT c.id, c.name, p " +
"FROM Company c LEFT JOIN c.companyProperties p where c.id = :id");
没有给我正确的结果(它只是 returns 属性 的值,而不是它们的键值列表)。
如何定义正确的查询来执行此操作?
我不喜欢你的 JPA 语法。在您的第一个查询中,您 selecting 了 Company
实体中的各个字段。但这不是 JPA 的工作方式;当您查询时,您会取回整个对象,您可以使用它访问您想要的任何字段。我建议改用以下代码:
TypedQuery<Company> query = entityManager.createQuery("from Company as c where c.id = :id", Company.class);
query.setParameter("id", companyId);
Company result = query.getSingleResult();
同样,对于第二个连接查询,我建议使用以下代码:
Query query = entityManager.createQuery("SELECT c" +
"FROM Company c LEFT JOIN c.companyProperties p WHERE c.id = :id");
query.setParameter("id", companyId);
List<Company> companies = query.getResultList();
只有 select 一个 Company
而不是 属性 实体的原因是属性将作为集合出现在 Company
class 中。假设公司和属性之间存在一对多,您可以从每个 Company
实体访问属性。
您希望在仅对特定字段执行 select 时获得完整的 Company
对象,这是不可能的。如果你真的想节省一些内存(在大多数情况下不会那么成功)并且 select 只是一些字段,那么你应该期待一个 List<Object[]>
:
List<Object[]> results = entityManager.createQuery("SELECT c.id, c.name, p " +
"FROM Company c LEFT JOIN c.companyProperties p where c.id = :id")
.setParameter("id", companyId)
.getResultList();
此处 results
将包含 selected 字段的单个数组。您可以使用 getSingleResult
,但请注意,如果未找到任何结果,它将抛出异常。