使用聚合休眠关系


@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,这样我就可以选择要在屏幕上显示的第一个项目。但当登录次数越来越多时,这是一个有点昂贵的操作。我应该做些什么来实现只选择最后一个登录日期;

  • 我可以使用Hibernate的@Formula通过它的构造函数和相关参数。但这将触发选择报告屏幕中的每个项目。

  • 我可以在业务层上实现另一种方法,这样一旦列表已加载;我可以启动另一个具有相关D_NAMES的HQL来获取D_NAME、loginDate配对并循环通过它们。哪个是从数据库中选择一个,但在应用程序上进行映射一边

那么,你有其他建议吗?比如用联接查询来同时选择设备和它的最后登录日期(而不是日期(?我认为这应该在某种程度上需要加入网站上的where子句,但后来我遇到了困难,无法想出如何做到这一点。

你的建议是什么?

顺便说一句,我没有发布设备的所有属性,但正如你可能意识到的那样,那里的许多属性和大多数其他属性都是通过使用HQL和LEFT OUTER JOIN连接到其他相关表/实体的select来获取的。

我通常创建一个数据库视图,比如device_summary_data,然后使用@SecondaryTable注释将其映射到device(或使用@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实现
  • 过滤、排序和分页可以根据任何其他属性应用于DB级别

我会通过反转映射并生成一些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添加到其中。

最新更新