Hibernate relation with aggregation

删除回忆录丶 提交于 2020-05-01 02:48:24

问题


@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;
}

My aim to display the last login date of the device on the report screens; I have implemented OneToMany relation between Device and LoginDate tables where it is using OrderBy to order loginDates descending so that I can choose the first item to display on the screen. But that's a bit expensive operation when it comes to the number of logins becomes larger and larger. What should I do to achieve to select only the last login date;

  • I can use @Formula of Hibernate to generate a Pojo via it's constructor with related parameters. But that will trigger number of selects per item in the report screen.

  • I can implement another method on the business layer so that once the list loaded; I can initiate another HQL with related D_NAMES to fetch the D_NAME, loginDate couples and loop through them. Which is one single select from the DB but a mapping work on the application side.

So do you have some other things for me to suggest something like a query with joins to select Device and it's last loginDate (not dates) at once ? I think This should somehow require where clause on the join site but then I hit the wall and could not figured out how to do that.

What is your suggestion ?

BTW I did not post all the properties of the Device but as you might realize that a lot of properties there and most of the other properties are getting fetched by a select with joins to other related tables/entites using HQL and LEFT OUTER JOINS.


回答1:


I normally create a database view say, device_summary_data and then map that to Device using the @SecondaryTable annotation (or as another Entity using @OneToOne).

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

View:

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:

@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;
}

Advantages over Hibernate's @Formula:

  • works with any JPA implementation
  • filtering, sorting and paging can be applied at the DB level as per any other property.



回答2:


I would do it by inverting the mapping and making some JPQL pageable / HQL query.

So your LoginDate would be something like:

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

and custom query (JPQL) would be something like

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

Depending on your other libraries / frameworks you would need to make the JPQL query to limit into one result only unless you are able to use simple native query like:

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

You might still leave Set<LoginDate> to your Device but add fetch=FetchType.LAZY to it for other purposes.



来源:https://stackoverflow.com/questions/53176186/hibernate-relation-with-aggregation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!