我有一个名为 direct_message 的表,它存储用户之间的直接消息列表,如下所示:
|身份证 |家长 ID | RECIPIENT_ID | 收件人 ID发件人 ID |标题|留言 |发送_AT | READ_AT
我想发回按 SENT_AT 排序的最新消息列表。我正在使用 JPA,因此查询将根据 RECIPIENT_ID 发回消息列表,如下所示:
@Repository
@Transactional(readOnly = true)
public interface DirectMessageRepository extends JpaRepository<DirectMessage, Long> {
Page<DirectMessage> findDirectMessageByRecipientId(Long recipientId, Pageable pageable);
}
这是我的实体类:
@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "direct_message")
public class DirectMessage {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "direct_message_sequence")
@SequenceGenerator(name = "direct_message_sequence", sequenceName = "direct_message_sequence", allocationSize = 1)
@Column(name = "id", nullable = false)
private Long id;
@ManyToOne
@JoinColumn(name = "parent_id")
private DirectMessage parent;
@ManyToOne
@JoinColumn(nullable = false, name = "sender_id")
private User sender;
@ManyToOne
@JoinColumn(nullable = false, name = "recipient_id")
private User recipient;
private String title;
@Lob
@Column(columnDefinition = "TEXT")
@Size(max = 4000)
private String message;
@Column(name = "sent_at")
private LocalDateTime sentAt;
private Boolean isRead = false;
@Column(name = "read_at")
private LocalDateTime readAt;
@Column(name = "can_reply")
private Boolean canReply;
}
但是,我的问题是,它会发回一条作为父级的消息以及一条包含它作为嵌套父级的子消息。这是一个简化的示例(省略了发件人、收件人和其他数据):
[{
"id": 1,
"parent": null,
"recipient": {},
"sender": {},
"title": "Message thread",
"message": "Hello"
}, {
"id": 2,
"parent": {
"id": 1,
"parent": null,
"recipient": {},
"sender": {},
"title": "Message thread",
"message": "Hello"
},
"recipient": {},
"sender": {},
"title": "Message thread",
"message": "This is the reply"
}]
如您所见,父消息(ID 1)被重复(作为其自己的行,并且还作为另一条消息的父消息,该消息是该消息的子消息。 JPA 有没有办法消除重复数据?并且仅在消息尚未属于另一个消息线程时才发回消息?或者,如果在 JPA 中不可能,是否有 SQL 查询可以完成这项工作?
不要使用实体作为 DTO!当然,在某些情况下这是可以接受的,但前提是你有意识地这样做。让我们把它排除在范围之外。 您更有可能在注释、获取、事务性、数据完整性、数据验证等方面遇到问题。
parent_id
字段添加另一个。假设您保持 parent
不变,您可以添加以下内容:@Column(name = 'parent_id', insertable = false, updatable = false)
private Long parentId;
它将代表家长在答案中的表现。
创建一个适当的 DTO 类,其中包含您需要发回的许多属性。让属性名称与实体类中的名称相同(最好但不是强制性的)。不要包含
parent
属性。
创建服务(类或接口+类),其方法会将您的实体转换为
dto
,反之亦然。它可以是简单的逐字段分配,也可以是 ModelMapper 的装饰器或其他有用的实现。
主要思想是将数据的传输和存储分开。
这确实是一个巨大的主题,似乎是数据传输和处理中的基本事物之一,并且不能通过这里的单一答案来涵盖。 查看 DTO 模式 和 Spring REST API 的实体到 DTO 转换 或仅通过关键字搜索实体和 DTO 之间的区别