【问题标题】:JPQL include elementCollection map in select statementJPQL 在 select 语句中包含 elementCollection 映射
【发布时间】:2017-12-20 09:16:54
【问题描述】:

我有一个具有多个属性的@Entity 类 Company,它引用了我的数据库中的一个公司表。其中一个代表 Map companyProperties,其中公司表由 company_properties 表扩展,属性以键值格式保存。

@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 查询并相应地检索地图。由于对象很大,我只需要在我的实体类中选择一些属性。我也不想按 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");

没有给我正确的结果(它只返回属性的值,而不是它们的键值列表)。

如何定义正确的查询来执行此操作?

【问题讨论】:

  • 你不能在结果子句中包含多值项,因为任何 JPQL 文档都会告诉你

标签: java jpa jpql


【解决方案1】:

您的 JPA 语法对我来说很有吸引力。在您的第一个查询中,您选择了 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();

之所以只选择Company 而不是属性实体,是因为属性会在Company 类中显示为一个集合。假设公司和属性之间存在一对多,您可以从每个Company 实体访问属性。

【讨论】:

  • 我不想检索整个实体,而只想检索某些特定属性。原因是,因为最终我将返回对象作为休息端点的结果。我不希望我的客户访问所有属性,而不是在查询后将它们设置为 null,我希望 JPQL 让我只检索我需要的内容
  • @SantiagoPerezChavez 然后发回你想要的任何东西。在任何情况下,即使实体有 NULL 占位符,当您转换为 JSON 时,它仍然会浪费空间。
  • 如果您真的想只检索 ceetain 字段,那么您可以使用本机 SQL 查询并返回由 Object 组成的结果集。但通常在 JPA 中,您会取回整个实体。
【解决方案2】:

您期望在仅对特定字段进行选择时获得完整的Company 对象,这是不可能的。如果你真的想节省一些内存(在大多数情况下不会那么成功)并且只选择一些字段,那么你应该期待List&lt;Object[]&gt;

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 将包含选定字段的单个数组。您可以使用getSingleResult,但请注意,如果没有找到结果,它会抛出异常。

【讨论】:

    猜你喜欢
    • 2013-10-18
    • 2011-06-09
    • 1970-01-01
    • 2014-10-11
    • 2011-08-18
    • 1970-01-01
    • 1970-01-01
    • 2017-01-21
    • 2012-07-30
    相关资源
    最近更新 更多