【发布时间】:2021-12-21 13:24:51
【问题描述】:
感谢您的宝贵时间! 我有一个复杂的场景,我试图在春季使用 JPA/Hibernate 进行映射。
首先,我有一个动态生成日期的函数,它输出以下内容:
id |starts_at |ends_at |frequency|separation|count|until|timezone_name|is_full_day|location_id |created_at |updated_at |version|name |description |picture|
------------------------------------+-----------------------+-----------------------+---------+----------+-----+-----+-------------+-----------+------------------------------------+-----------------------+-----------------------+-------+-----------------------------+-----------------+-------+
d255afb6-3730-4845-8e5e-18baa909dcfe|2021-12-21 18:00:00.000|2021-12-22 02:00:00.000|ONCE | 1| | |UTC |false |fe88fa63-360e-4281-a383-35826a759e59|2021-10-29 00:22:46.109|2021-10-29 00:22:46.109| 0| | | |
e7193453-4c1b-433d-8127-5eedf2efd011|2022-02-20 20:00:00.000|2022-02-20 23:00:00.000|WEEKLY | 1| | |UTC |false |fe88fa63-360e-4281-a383-35826a759e59|2021-11-02 19:23:31.029|2021-11-02 19:23:31.029| 0|Festa da minha graaande amiga|A Fofinha nao vai| |
e7193453-4c1b-433d-8127-5eedf2efd011|2022-02-21 20:00:00.000|2022-02-21 23:00:00.000|WEEKLY | 1| | |UTC |false |fe88fa63-360e-4281-a383-35826a759e59|2021-11-02 19:23:31.029|2021-11-02 19:23:31.029| 0|Muito massa essa fita |Mudanca drastica | |
e7193453-4c1b-433d-8127-5eedf2efd011|2022-02-22 20:00:00.000|2022-02-22 23:00:00.000|WEEKLY | 1| | |UTC |false |fe88fa63-360e-4281-a383-35826a759e59|2021-11-02 19:23:31.029|2021-11-02 19:23:31.029| 0|Festa da minha graaande amiga|A Fofinha nao vai| |
e7193453-4c1b-433d-8127-5eedf2efd011|2022-02-24 20:00:00.000|2022-02-24 23:00:00.000|WEEKLY | 1| | |UTC |false |fe88fa63-360e-4281-a383-35826a759e59|2021-11-02 19:23:31.029|2021-11-02 19:23:31.029| 0|Festa da minha graaande amiga|A Fofinha nao vai| |
e7193453-4c1b-433d-8127-5eedf2efd011|2022-02-25 20:00:00.000|2022-02-25 23:00:00.000|WEEKLY | 1| | |UTC |false |fe88fa63-360e-4281-a383-35826a759e59|2021-11-02 19:23:31.029|2021-11-02 19:23:31.029| 0|Festa da minha graaande amiga|A Fofinha nao vai| |
重要的部分是:id(相同,因为它是数据库中的同一个实体;starts_at:事件的初始日期和元数据部分(与另一个表的左连接);
这是输出上述示例的查询:
select
e.*,
coalesce (em.name,
em2.name) as name,
coalesce (em.description ,
em2.description) as description,
coalesce (em.picture ,
em2.picture) as picture
from
recurring_events_for('2021-12-03T10:15:30',
'2022-12-03T10:15:30',
'UTC',
5,
false) e
left join events_metadata em on
em.event_id = e.id
and em.starts_at = e.starts_at
left join events_metadata em2
on
em2.event_id = e.id
and em2.starts_at = (
select
MIN(starts_at)
from
events_metadata
where
event_id = e.id
limit 1)
我如何使用 Hibernate 进行映射:
事件(recurring_events_for 的输出):
@Entity
@Table(name = "events")
public class Event extends BaseEntity {
@Column
private LocalDateTime startsAt;
@Column
private LocalDateTime endsAt;
@Column
@Enumerated(EnumType.STRING)
private EventFrequency frequency;
@Column(nullable = false)
private Integer separation;
@Column
private Integer count;
@Column
private LocalDate until;
@Column(nullable = false)
private String timezoneName;
@Column(nullable = false)
private boolean isFullDay;
@ManyToMany
@JoinTable(
name = "event_organizers",
joinColumns = @JoinColumn(name = "event_id"),
inverseJoinColumns = @JoinColumn(name = "user_id"))
private Set<User> organizers;
@OneToMany(mappedBy = "product")
private Set<EventProduct> products;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
@JoinColumn(name = "location_id")
private Location location;
@OneToMany(mappedBy = "event",
orphanRemoval = true,
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
private Set<EventRecurrence> recurrences;
@OneToOne(mappedBy = "id.event", optional = false, orphanRemoval = true, fetch = FetchType.LAZY)
private EventMetadata metadata;
event_metadata 表:
@Table(name = "events_metadata")
@Entity
public class EventMetadata extends BaseEntityNoId {
@EmbeddedId
private EventMetadataPK id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private String description;
@Column
private String picture;
@Column(nullable = false)
private boolean isPrivate;
@Column(nullable = false)
private boolean showGuestList;
@Column(nullable = false)
private boolean friendCanInviteFriends;
@OneToMany(mappedBy = "event", orphanRemoval = true)
private Set<EventAttendance> eventAttendances;
嵌入式 PK:
@Embeddable
public class EventMetadataPK implements Serializable {
@OneToOne(orphanRemoval = true)
@JoinColumn(name = "event_id", updatable = false, insertable = false)
private Event event;
@Column(nullable = false)
private LocalDateTime startsAt;
最后,我在 JPA 世界中如何称呼它:
@Query(nativeQuery = true,
value = "select e.*, coalesce (em.*, em2.*) as metadata " +
"from recurring_events_for(:range_start, :range_end, :time_zone, :events_limit, false) e " +
"left join events_metadata em on em.event_id = e.id and em.starts_at = e.starts_at " +
"left join events_metadata em2 " +
"on em2.event_id = e.id " +
"and em2.starts_at = (select MIN(starts_at) from events_metadata where event_id = e.id limit 1)")
List<Event> getEvents(@Param("range_start") LocalDateTime rangeStart,
@Param("range_end") LocalDateTime rangeEnd,
@Param("time_zone") String timezone,
@Param("events_limit") Integer limit);
问题是,嵌入 PK 中映射的 starts_at 列实际上与 recurring_events_for 的结果连接,因此(我认为)不可能使用 Hibernate 映射它。我该如何处理这种情况??
谢谢!
【问题讨论】:
-
您在尝试这个时遇到了什么问题?查询中的异常?在部署中?究竟是哪一个?或者它不能被映射到
Event类 -
我猜你已经知道了,但只是为了确定。对于复杂的情况,您可以直接在查询中使用构造函数。例如,您可以这样做:
select new Event(e.id, e.name) from ...。尽管在我测试的上一个版本中,您需要 sepcify 完全限定的类名(使用完整的包)。但考虑到您需要更多对象(因为@Embeded),我还没有测试是否可以将另一个构造函数嵌套为外部构造函数的参数,这意味着select new Event(e.id, e.name, new Metadata(m.id, m.dataX)) from ... -
您使用什么 SQL 数据库/方言?为什么输出上述示例的查询与
@Query注解中使用的查询不同?
标签: java spring spring-boot hibernate spring-data-jpa