[英]Custom Join with composite key Hibernate
謝謝你的時間! 我有一個復雜的場景,我試圖在春天用 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
實體類似於:@Entity
@Table(name = "events")
@SqlResultSetMapping(
name = "recurring_events_mapping",
classes = {
@ConstructorResult(
targetClass = Event.class,
columns = {
@ColumnResult(name = "ID", type = String.class),
@ColumnResult(name = "STARTS_AT", type = LocalDateTime.class),
@ColumnResult(name = "ENDS_AT", type = LocalDateTime.class),
@ColumnResult(name = "FREQUENCY", type = String.class),
@ColumnResult(name = "SEPARATION", type = Integer.class),
@ColumnResult(name = "COUNT", type = Integer.class),
@ColumnResult(name = "UNTIL", type = LocalDate.class),
@ColumnResult(name = "TIMEZONE_NAME", type = String.class),
@ColumnResult(name = "IS_FULL_DAY", type = Boolean.class),
@ColumnResult(name = "LOCATION_ID", type = String.class),
@ColumnResult(name = "CREATED_AT", type = LocalDateTime.class),
@ColumnResult(name = "UPDATED_AT", type = LocalDateTime.class),
@ColumnResult(name = "VERSION", type = Integer.class),
// metadata
@ColumnResult(name = "NAME", type = String.class),
@ColumnResult(name = "DESCRIPTION", type = String.class),
@ColumnResult(name = "PICTURE", type = String.class)
}
)
}
)
@NamedNativeQuery(
name = "Event.RecurringEventsQuery",
query = "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_mock e " + // just for test
"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)" +
"where :time_zone IS NOT NULL " + // just for test
" and :events_limit > 0 " + // just for test
" and :range_start IS NOT NULL " + // just for test
" and :range_end IS NOT NULL ", // just for test
resultSetMapping = "recurring_events_mapping")
@Query(name = "Event.RecurringEventsQuery")
List<Event> getEvents(
@Param("range_start") LocalDateTime rangeStart,
@Param("range_end") LocalDateTime rangeEnd,
@Param("time_zone") String timezone,
@Param("events_limit") Integer limit
);
List<Event> findAll();
public Event() {
}
public Event(
String id,
LocalDateTime startsAt,
LocalDateTime endsAt,
String frequency,
Integer separation,
Integer count,
LocalDate until,
String timezoneName,
Boolean isFullDay,
String locationId,
LocalDateTime createdAt,
LocalDateTime updatedAt,
Integer version,
// metadata
String name,
String description,
String picture) {
this.id = id;
this.startsAt = startsAt;
this.endsAt = endsAt;
this.frequency = EventFrequency.valueOf(frequency);
this.separation = separation;
this.count = count;
this.until = until;
this.timezoneName = timezoneName;
this.isFullDay = isFullDay;
this.location = new Location(locationId);
this.metadata = new EventMetadata(id, startsAt, name, description, picture);
}
在這里你可以找到丑陋的 POC 存儲庫https://bitbucket.org/kasptom/stackoverflow-69887977
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.