我有以下“父母”:
@Entity
@Table(name = "messages")
@SequenceGenerator(name = "messageSequence", sequenceName = "message_sequence")
public class Message {
@Id
@Column(name = "message_id")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "messageSequence")
Long messageId;
@OneToMany(mappedBy = "message", cascade=CascadeType.ALL)
List<Recipient> recipients = new ArrayList<>();
public void addRecipient(Recipient r) {
r.setMessage(this);
recipients.add(r);
}
@Column(name = "message_body")
String body;
// Constructors/Getters/Setters
...
}
收件人“孩子”:
@Entity
@Table(name = "message_recipients")
public class Recipient {
@EmbeddedId
private RecipientId recipientId;
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "message_id")
private Message message;
public void setMessage(Message msg) {
this.message = msg;
}
public Recipient(Message msg, String name) {
this.id = new RecipientId(msg, name);
this.message = msg;
}
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode(Object o) { return key.hashCode(); }
}
使用组合键:
@Embeddable
public class RecipientId implements Serializable {
@Column(name = "message_id")
Long messageId;
@Column(name = "message_to")
String messageTo;
@Column(name = "message_timestamp")
LocalDateTime messageTimestamp;
public RecipientId(Message msg, String messageTo) {
this.messageId = msg.messageId;
this.messageTo = messageTo;
this.messageTimestamp = LocalDateTime.now();
}
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode() {
return Objects.hash(messageId, messageTo, messageTimestamp);
}
}
我有以下测试代码:
@Bean
public void makeMessage(MessageRepository messages) {
Message newMsg = new Message();
newMsg.addRecipient(new Recipient(newMsg, "recipientName"));
newMsg.setBody("This is a test message");
messages.save(newMsg);
}
执行makeMessage()时,我在调试输出中可以看到Message获得了生成的MessageId值,但是当持久存储收件人时,复合键的messageId为null,从而导致事务失败。
2018-11-27 14:49:54.158 DEBUG 2791 --- [ restartedMain] org.hibernate.SQL :
Hibernate:
values
nextval for amessage_sequence
2018-11-27 14:49:54.190 DEBUG 2791 --- [ restartedMain] org.hibernate.SQL :
Hibernate:
insert
into
messages
(body, message_code)
values
(?, ?)
2018-11-27 14:49:54.191 TRACE 2791 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [This is a test message]
2018-11-27 14:49:54.193 TRACE 2791 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [BIGINT] - [2922079]
2018-11-27 14:49:54.196 DEBUG 2791 --- [ restartedMain] org.hibernate.SQL :
Hibernate:
insert
into
message_recipient
(timestamp, message_id, message_to)
values
(?, ?, ?)
2018-11-27 14:49:54.196 TRACE 2791 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [TIMESTAMP] - [2018-11-27 14:49:54.141]
2018-11-27 14:49:54.196 TRACE 2791 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [BIGINT] - [null]
2018-11-27 14:49:54.196 TRACE 2791 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [RecipientName]
2018-11-27 14:49:54.199 WARN 2791 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: -407, SQLState: 23502
2018-11-27 14:49:54.199 ERROR 2791 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : DB2 SQL Error: SQLCODE=-407, SQLSTATE=23502, SQLERRMC=TBSPACEID=7, TABLEID=21, COLNO=1, DRIVER=4.19.26
我已经尽力尝试使它起作用的所有可能性,包括@IdClass,但始终为null。从我可以在网上找到的所有内容来看,这应该可行。我发现了一个或两个类似的SO问题,但是都没有解决复合键的具体问题,其中复合字段之一是父ID。
我认为我可以通过以下两种方法来解决此问题:将消息和收件人保持在两个单独的状态中(持久消息,获取ID,然后创建并保留收件人),但是据我所知,这应该是>工作...
答案 0 :(得分:1)
这是因为您需要使用message_id
将RecipientId
映射到类@MapsId("messageId")
中,因此您可以执行以下操作:
@Entity
@Table(name = "message_recipients")
public class Recipient {
@EmbeddedId
private RecipientId recipientId;
@MapsId("messageId")
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "message_id")
private Message message;
public void setMessage(Message msg) {
this.message = msg;
}
public Recipient(Message msg, String name) {
this.id = new RecipientId(msg, name);
this.message = msg;
}
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode(Object o) { return key.hashCode(); }
}