当前位置: 首页 > 知识库问答 >
问题:

JPA-计算列作为实体类属性?

井唯
2023-03-14

对JPA来说比较新,所以我有一个架构问题。假设我有多对一关系的员工和部门表(即许多员工为一个部门工作):

EMPLOYEE
  EMPLOYEE_ID
  EMPLOYEE_NAME
  DEPARTMENT_ID 

DEPARTMENT
  DEPARTMENT_ID
  DEPARTMENT_NAME

所以我可以为员工和部门定义合适的实体,没有问题。但是,在一个视图中,我想显示部门列表,其中包含为该部门工作的员工数量,类似于这样:

SELECT D.DEPARTMENT_NAME, 
       (SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID) NUMBER_OF_EMPLOYEES
FROM DEPARTMENT D

我只是不确定使用JPA实现这一目标的正确策略是什么。。。我不想总是获取部门实体的员工数量,因为需要时只有一个视图。

看起来HiberNate的@公式是一种可能的方法,但是它不符合JPA标准。

共有3个答案

沈成天
2023-03-14

您可以在实体中创建一个成员作为附加列,然后在查询中用别名引用它。@column注释中的列名必须与别名匹配。

比如,对于原始查询,可以添加countEmployees成员,如下所示。还要添加insertable=falseupdateable=false,这样实体经理就不会试图将其包含在insert或update语句中:

public class Department {

    @Column(name="DEPARTMENT_ID")
    Long departmentId;

    @Column(name="DEPARTMENT_NAME")
    String departmentName;

    @Column(name="countEmployees", insertable=false, updatable=false)
    Long countEmployees;

    //accessors omitted

}

你的问题是:

SELECT D.DEPARTMENT_NAME, 
(SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID) AS countEmployees
FROM DEPARTMENT D

这在使用Spring数据Jpa存储库时也适用。

金赤岩
2023-03-14

选项1:我建议这样做是因为你不喜欢MattR建议的构造函数路线。你多次提到“视图”这个词,我知道你是在向用户谈论视图,但是为什么不在你的数据库中设置一个包含计算列的视图,然后创建一个映射到计算列的只读实体呢?

选项2:回应您关于不想创建视图的评论。您可以创建一个容器对象来保存实体和计算列,然后就像马特建议的那样,在选择中使用新的。比如:

public class DepartmentInfo {
    private Department department;

    // this might have to be long or something
    // just see what construct JPA tries to call
    private int employeeCount;

    public DepartmentInfo( Department d, int count ) { 
        department = d;
        employeeCount = count;
    }
    // getters and setters here
}

然后你的选择变成

SELECT new my.package.DepartmentInfo( D, 
       (SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID))
FROM DEPARTMENT D

有了它,你可以使用DepartmentInfo来获取你感兴趣的房产。

上官琦
2023-03-14

您可以使用“new”语法在QL中创建任何对象——您的类只需要一个接受查询返回的值的构造函数。

例如,对于像Department雇员计数这样的类,使用构造函数:

public DepartmentEmployeeCount(String departmentName, Integer employeeCount)

你可以使用QL,比如:

SELECT NEW DepartmentEmployeeCount(D.DEPARTMENT_NAME, count(E.id)) from Department D left join D.employees E GROUP BY D.DEPARTMENT_NAME

或者,如果只是选择count(*),则可以简单地将查询结果转换为一个数字。

或者,若要在没有Department雇员计数类的情况下执行同样的操作,您可以省略new,因此:

SELECT D.DEPARTMENT_NAME, count(E.id)    

这将返回一个列表

要回答评论中后面的问题,要填充一个部门的所有字段加上一个临时employeeCount字段,一个建议是执行两个查询。这仍然比原始查询(每个员工计数的子选择)更有效。

一个去查询部门的人读了这么多

SELECT D from Department D

给你一个列表

然后,第二个查询返回一个临时数组:

SELECT D.DEPARTMENT_ID, count(E.id) from Department D left join D.employees E GROUP BY D.DEPARTMENT_ID

给你一个列表

然后使用第二个列表来更新第一个列表上的瞬态计数属性。(你可以试着选择进入一个地图来使这种查找更容易,但我认为这是一个Hibernate特性)。

 类似资料:
  • 问题内容: 我只是在Glassfish 3(持久性提供程序是EclipseLink)上运行的简单Java Web应用程序中了解JPA。到目前为止,我真的很喜欢它(除了netbeans / glassfish交互中的错误),但是我想做到的事情我不确定该怎么做。 我有一个映射到数据库表的实体类(文章)。我正在尝试对返回已计算列的数据库进行查询,但无法弄清楚如何设置Article类的属性,以便在调用查询

  • 我有两个表审查和bedrijfsgegevens。Review表有一个主键(reviewId)和一个外键(bedrijfId)。BedrijfId是Bedrijfsgegevens表中的主键(作为Id)。我遇到了这个问题,因为我试图在Review表中添加一个bedrijfId,而Bedrijfgegevens表中不存在这个行,因此得到了一个异常。 我尝试使用@manytoone和@joincolu

  • 当我将Java EE应用程序部署到Glassfish时,我有一个非常奇怪的问题。我有一个Eclipse EAR项目,它引用了一个Web项目(包含一个servlet),一个EJB项目(有一个EJB)和一个JPA项目(有一个@Entity)。在我的 servlet 中,我调用 EJB,它又执行以下查询: 在上面代码的第三行,我得到了一个异常: 我已经调试了上面提到的Hibernate类,即Metamo

  • 我试图找到一种方法,在JPQL查询中放置一个计算字段,以映射到Spring Boot中的实体。 我刚才的例子列出了一个静态数字,但我打算将来也将其用于聚合。 我在尝试运行查询时不断收到以下消息: “类[Ljava.lang.Object;不能强制转换为类com.School([Ljava.lang.Object;位于加载器“bootstrap”的模块java.base中;com.School位于加

  • 我目前的项目是用JavaFX完成的。我使用属性将(双向)视图字段绑定到bean(使用JFXtras的BeanPathAdapter)。 我选择用JPA和ObjectDB作为模型。 这是我第一次在独立的项目中使用JPA,这里我面临的是托管实体的问题。 实际上,我将托管实体绑定到视图字段,当视图字段的值更改时,实体会更新...和数据库也是如此。 我正在尝试找到一种手动保存/合并实体的方法,以便我可以询

  • 我有一个使用Postgre 9.3和JPA2.1(Hibernate实现)的Spring MVC应用程序。我有一个类'电影',其中有一组评论。我想写一个JPA NamedQuery,它返回我所有的电影细节,但只有批准的评论。评论可以有其他状态,但我想只显示批准的评论。 我的班级如下所示: 我写的查询不会过滤评论并返回包含所有评论的电影;它的工作原理与上面显示的findMovieById查询相同。