我正在创建一个聊天系统,并且具有以下数据库架构(与核心问题无关的所有内容均已删除)。
线程代表两个参与者之间的对话。创建(持久化)新线程时,应创建两个参与者。一个用于发送方,一个用于接收方(消息已添加到线程中,但在这种情况下不相关)。因此,我已将两个数据库表映射到两个实体。
@Entity
@Table(name = "participant")
public class Participant {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private int id;
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Thread.class, optional = false)
@JoinColumn(name = "thread_id")
private Thread thread;
// Getters and setters
}
@Entity
@Table(name = "thread")
public class Thread {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private int id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "thread", targetEntity = Participant.class, cascade = CascadeType.ALL)
private Set<Participant> participants = new HashSet<>();
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Participant.class, cascade = CascadeType.ALL, optional = false)
@JoinColumn(name = "sender_id")
private Participant sender;
@ManyToOne(fetch = FetchType.LAZY, targetEntity = Participant.class, cascade = CascadeType.ALL, optional = false)
@JoinColumn(name = "receiver_id")
private Participant receiver;
// Getters and setters
}
为了方便起见,从Thread
实体开始,participants
关联应包含线程中的所有参与者,而sender
和分别receiver
包含对发送者和接收者的引用。因此,数据库中仅应保留两个参与者。这是我为保留新线程而编写的代码:
Thread thread = new Thread();
Participant sender = new Participant();
sender.setThread(thread);
Participant receiver = new Participant();
receiver.setThread(thread);
thread.setSubject(subject);
thread.setSender(sender);
thread.setReceiver(receiver);
Set<Participant> participants = new HashSet<>(2);
participants.add(sender);
participants.add(receiver);
thread.setParticipants(participants);
Thread saved = this.threadRepository.save(thread);
这将引发以下异常。
org.hibernate.TransientPropertyValueException:非null属性引用一个瞬态值-必须在当前操作之前保存瞬态实例:com.example.thread.entity.Participant.thread-> com.example.thread.entity.Thread
我cascade
在两个实体上尝试了多种属性变体,但是在所有情况下都会抛出相同的异常(尽管瞬态属性不同)。从逻辑上讲,该方法应该没有问题,因为所有要做的事情是Thread
先保留实体,以便参与者在自己持久存储之前获得生成的ID。
我的映射是否有问题,或者是什么问题?谢谢!
根据我的评论,提供了一个更详细的答案,要求提供它作为答案。
尝试解决具有不同级联类型,joincolumns和其他休眠注释的问题。通常是解决此类问题的错误方法。特别是级联应该以与您使用的方式不同的方式使用,您现在应该将其从此映射中删除。始终根据您要使用的模型来查看模型的语义/含义。级联参与者可能不是您想要的,因为在大多数情况下,参与者将创建并维护线程的独立性。因此,不要尝试在没有实际业务案例的情况下使用级联简化单个实体的保存过程。
我建议您拆分它,并独立于参与者创建/保存Thread对象。它可能需要多几行代码,但是从长远来看它们更容易理解并且更易于维护。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句