Hibernate 与聚合的关系

Hibernate relation with aggregation

@Entity
public class Device {
    private long id;
    private String deviceName; //column D_NAME
    private Set<LoginDate> loginDates;
}

/**
    Audit table being filled by some other processes on the network
 */

@Entity
public class LoginDate {
    private long id; //pk
    private String deviceName; //column D_NAME
    private Date loginDate;
}

我的目标是在报告屏幕上显示设备的最后登录日期;我在 DeviceLoginDate 表之间实现了 OneToMany 关系,其中它使用 OrderBy 对 loginDates 进行降序排序,以便我可以选择要在屏幕上显示的第一项。但是当登录数量越来越大时,这是一个有点昂贵的操作。我应该怎么做才能达到 select 仅上次登录日期;

那么,您是否还有其他一些建议可以建议我使用查询连接 select 设备并且它是最后一次登录日期(不是日期)?我认为这应该以某种方式要求加入站点上的 where 子句,但后来我碰壁了,不知道该怎么做。

你有什么建议?

顺便说一句,我没有 post 设备的所有属性,但你可能会意识到那里的很多属性和大多数其他属性都是通过 select 获取的,并连接到其他相关 tables/entites 使用 HQL 和 LEFT OUTER JOINS。

我通常创建一个数据库视图,比如 device_summary_data,然后使用 @SecondaryTable 注释将其映射到设备(或使用 @OneToOne 作为另一个实体)。

https://docs.oracle.com/javaee/7/api/javax/persistence/SecondaryTable.html

查看:

create view device_summary_data as 
select d.id as device_id, max(l.login_date), count(l.device_name)
from logins l
inner join devices d on d.D_NAME = l.D_NAME
group by d.id

实体:

@Entity
@SecondaryTable(name = "device_summary_data",  
   pkJoinColumns=@PrimaryKeyJoinColumn(name="device_id", referencedColumnName = "id"))
public class Device {
    private long id;

    private String deviceName; 

    private Set<LoginDate> loginDates;

    @Column(table="device_summary_data", insertable=false, updateable = false)
    private Date lastLogin;

    @Column(table="device_summary_data", insertable=false, updateable = false)
    private Integer numberOfLogins;
}

相对于 Hibernate 的优势 @Formula

  • 适用于任何 JPA 实现
  • 过滤、排序和分页可以按照任何其他 属性.
  • 在数据库级别应用

我会通过反转映射并制作一些 JPQL 可分页/HQL 查询来实现。

所以你的 LoginDate 会是这样的:

@Entity
public class LoginDate {
    private long id; //pk
    @ManyToOne
    private Device device;
    private Date loginDate;
}

自定义查询 (JPQL) 类似于

SELECT ld FROM LoginDate ld WHERE device=:device ORDER BY ld.loginDate DESC

根据您的其他库/框架,您需要将 JPQL 查询限制为一个结果,除非您能够使用简单的 native 查询如:

SELECT ld.logindate
FROM logindate ld
WHERE ld.device_id=:device_id
ORDER BY ld.logindate DESC
LIMIT 1

您可能仍将 Set<LoginDate> 保留在您的 Device 中,但添加 fetch=FetchType.LAZY 用于其他目的。