postgresql 将来自联接类的属性包括到自动生成的JPA选择中

nbnkbykc  于 2023-08-04  发布在  PostgreSQL
关注(0)|答案(1)|浏览(118)

使用以下示例类,当我尝试列出按雇员的lastName属性排序的leaves时,我得到以下错误消息:
org.postgresql.util.PSQLException:错误:对于SELECT DISTINCT,ORDER BY表达式必须出现在选择列表中
用于存储员工休假的类:

@Entity(name = "Leave")
data class LeaveEntity(
  @NotNull
  @ManyToOne()
  @JoinColumn(name = "employeeId")
  var employee: EmployeeEntity,
  ... 
)

字符串
用于存储员工的类:

@Entity(name = "Employee")
class EmployeeEntity(
  @NotNull
  @GeneratedValue(strategy = GenerationType.AUTO)
  var id: UUID? = null,
  @NotNull
  var firstName: String,
  @NotNull
  var lastName: String,
  ...
  @OneToMany(mappedBy = "employee", targetEntity = LeaveEntity::class)
  var leave: MutableList<LeaveEntity> = mutableListOf(),
)


在我的脑海中,它们应该是连接的,所以排序将是可能的,但似乎并非如此。
我还启用了jpa来显示它生成的sql查询,它们看起来像这样:

Hibernate: 
    select
        distinct leaveentit0_.id as id1_5_,
        leaveentit0_.crdat as crdat2_5_,
        leaveentit0_.crby as crby3_5_,
        leaveentit0_.mddat as mddat4_5_,
        leaveentit0_.mdby as mdby5_5_,
        leaveentit0_.tenant_id as tenant_i6_5_,
        leaveentit0_.comment as comment7_5_,
        leaveentit0_.employee_id as employe12_5_,
        leaveentit0_.status as status8_5_,
        leaveentit0_.time_end as time_end9_5_,
        leaveentit0_.time_start as time_st10_5_,
        leaveentit0_.type as type11_5_ 
    from
        leave leaveentit0_ 
    left outer join
        employee employeeen1_ 
            on leaveentit0_.employee_id=employeeen1_.id 
    where
        leaveentit0_.tenant_id=? 
    order by
        employeeen1_.last_name asc limit ?


我想我应该以某种方式显式地将employeeName添加到select中,但还没有找到这样做的方法。这是正确的解决方案吗?还是问题来自这两个类的连接方式,只要改变它就可以解决问题?

dbf7pr2w

dbf7pr2w1#

对于我的情况,解决方案是使用@Formula注解。问题是查询没有包括默认情况下的每个必要字段,因为它们将在数据库调用结束后填写。但是,由于我要求数据按连接实体的一个字段排序,而整个连接实体并没有加载,因此它不能要求名称字段,这就是问题出现的原因。
为了连接元素,我必须应用@Formula注解。用上述情况的例子可以更容易地解释。在注解中,您必须编写一个简单的SQL,在某个字段上将两个表连接在一起。在employees.lastName的情况下,它看起来像这样:

@Entity(name = "Leave")
data class LeaveEntity(

  @NotNull
  @ManyToOne
  @JoinColumn(name = "employeeId")
  var employee: EmployeeEntity,
  ...
) : TenantOwnedBaseEntity() {

  @Formula("(select employee.last_name from employee where employee.id = employee_id)")
  var employeeLastName: String = ""
}

字符串
这样,当调用DB查询时,我们将填写employeeLastName字段,得到类似于“虚拟列”的内容。我们没有将它存储在数据库中,但是当我们调用查询时,我们将拥有它,并且能够按此值对结果进行排序。
请注意,这样,您将不得不使用employeeLastName而不是调用employee.lastName作为筛选的字段,因为这是存储值的字段。
现在这个解决方案应该只在所有包含的类都在同一个数据库中时才有效,但在我的问题中,情况就是这样。
另一个解决方案是在LeaveEntity类中单独包含employeeLastName属性,尽管这个解决方案并不漂亮。这将导致冗余的数据存储,但在实体位于不同数据库中的情况下,它将解决按字段排序的问题。该值也必须被维护,因为更改连接的EmployeeEntity不会自动更改存储在employeeLastName中的值,这需要手动完成。

相关问题