分离的实体传递给持久化,多对多 JPA
detached entity passed to persist, many to many JPA
您好,我正在尝试创建一个新请求,并且 link 它与 db 上的一个已经创建的人一起创建,但是我遇到了一个错误。
@Entity
@Table(name = "TG_REQUEST")
public class TgRequest {
@Id
@SequenceGenerator(name = "TG_REQUEST", sequenceName = "S_TG_REQUEST", allocationSize = 1)
@GeneratedValue(generator = "TG_REQUEST")
@Getter
@Setter
private Long idRequest;
@OneToMany(mappedBy = "tgRequest", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
@Getter
@Setter
private Set<TgRequestPerson> tgRequestPersons = new HashSet<>();
public TgRequest() {
}
public void addTgRequestPerson(TgRequestPerson tgRequestPerson) {
tgRequestPersons.add(tgRequestPerson);
tgRequestPerson.setTgRequest(this);
}
public void removeTgRequestPerson(TgRequestPerson tgRequestPerson) {
this.tgRequestPersons.remove(tgRequestPerson);
tgRequestPerson.setTgRequest(null);
}
}
@Entity
@Table(name = "TG_PERSON")
public class TgPerson {
@Id
@SequenceGenerator(name = "TG_PERSON", sequenceName = "S_TG_PERSON", allocationSize = 1)
@GeneratedValue(generator = "TG_PERSON")
@Getter
@Setter
private Long idPerson;
@OneToMany(mappedBy = "tgPerson")
@Getter
@Setter
private Set<TgRequestPerson> tgRequestPersons = new HashSet<>();
public TgPerson() {
}
public void addTgRequestPerson(TgRequestPerson tgRequestPerson) {
tgRequestPersons.add(tgRequestPerson);
tgRequestPerson.setTgPerson(this);
}
public void removeTgRequestPerson(TgRequestPerson tgRequestPerson) {
this.tgRequestPersons.remove(tgRequestPerson);
tgRequestPerson.setTgPerson(null);
}
}
@Entity
@Table(name = "TG_REQUEST_PERSON")
public class TgRequestPerson {
@EmbeddedId
@Getter
@Setter
private TgRequestPersonKey idRequestPerson;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("idRequest")
@JoinColumn(name = "ID_REQUEST")
@Getter
@Setter
private TgRequest tgRequest;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("idPerson")
@JoinColumn(name = "ID_PERSON")
@Getter
@Setter
private TgPerson tgPerson;
public TgRequestPerson() {
}
}
@Embeddable
public class TgRequestPersonKey implements Serializable {
@Column(name = "ID_REQUEST")
private Long idRequest;
@Column(name = "ID_PERSON")
private Long idPerson;
public TgRequestPersonKey() {
}
public Long getIdRequest() {
return idRequest;
}
public void setIdRequest(Long idRequest) {
this.idRequest = idRequest;
}
public Long getIdPerson() {
return idPerson;
}
public void setIdPerson(Long idPerson) {
this.idPerson = idPerson;
}
}
要保存的代码(新请求 link 到 db 上的现有人员):
TgRequest tgRequest = new TgRequest();
Long idPerson = 1; //Person already exists on db, with id = 1
TgPerson tgPerson = new TgPerson();
tgPerson.setIdPerson(idPerson)
TgRequestPerson tgRequestPerson = new TgRequestPerson();
TgRequestPersonKey tgRequestPersonKey = new TgRequestPersonKey();
tgRequestPersonKey.setIdRequest(tgRequest.getIdRequest());
tgRequestPersonKey.setIdPerson(idPerson);
tgRequest.addTgRequestPerson(tgRequestPerson);
tgPerson.addTgRequestPerson(tgRequestPerson);
tgRequestPerson.setIdRequestPerson(tgRequestPersonKey);
requestRepository.save(tgRequest);
我在看什么
插入tgRequest; --> 生成一个新的 id
插入 tgRequestPerson(idRequest = 新创建,idPerson = 1)
(link 数据库上已经有人的新创建请求)
失败了。
错误
org.hibernate.PersistentObjectException: detached entity passed to persist: TgPerson
要更新的代码(link 一个创建的请求和一个创建的人)
TgRequest tgRequest = requestRepository.findByIdRequest(1); //Request already exists
Long idPerson = 1; //Person already exists on db, with id = 1,
TgPerson tgPerson = new TgPerson();
tgPerson.setIdPerson(idPerson)
TgRequestPerson tgRequestPerson = new TgRequestPerson();
TgRequestPersonKey tgRequestPersonKey = new TgRequestPersonKey();
tgRequestPersonKey.setIdRequest(tgRequest.getIdRequest());
tgRequestPersonKey.setIdPerson(idPerson);
tgRequest.addTgRequestPerson(tgRequestPerson);
tgPerson.addTgRequestPerson(tgRequestPerson);
tgRequestPerson.setIdRequestPerson(tgRequestPersonKey);
requestRepository.save(tgRequest);
期待中
插入 tgRequestPerson(idRequest = 1,idPerson = 1)有效!
那么,我怎样才能使保存代码生效?
错误发生是因为设置了对象的(tgPerson)ID。 Hibernate 区分瞬态对象和分离对象,save
仅适用于瞬态对象。如果 save
断定对象已分离(因为设置了 ID,它会分离),它将 return 出现“已分离的对象传递给持久化”错误。您可以找到更多详细信息 here and here.
但是,这仅适用于您已指定要自动生成主键的情况:如果该字段配置为始终手动设置,则您的代码有效。
所以你需要删除那些注释
@SequenceGenerator(name = "TG_PERSON", sequenceName = "S_TG_PERSON", allocationSize = 1)
@GeneratedValue(generator = "TG_PERSON")
或者调用saveOrUpdate方法
您将不得不使用 getOne
,它在幕后使用 entityManager.getReference
来引用现有对象。
TgRequest tgRequest = requestRepository.findByIdRequest(1); //Request already exists
Long idPerson = 1; //Person already exists on db, with id = 1,
TgPerson tgPerson = personRepository.getOne(idPerson);
TgRequestPerson tgRequestPerson = new TgRequestPerson();
TgRequestPersonKey tgRequestPersonKey = new TgRequestPersonKey();
tgRequestPersonKey.setIdRequest(tgRequest.getIdRequest());
tgRequestPersonKey.setIdPerson(idPerson);
tgRequest.addTgRequestPerson(tgRequestPerson);
tgPerson.addTgRequestPerson(tgRequestPerson);
tgRequestPerson.setIdRequestPerson(tgRequestPersonKey);
requestRepository.save(tgRequest);
您好,我正在尝试创建一个新请求,并且 link 它与 db 上的一个已经创建的人一起创建,但是我遇到了一个错误。
@Entity
@Table(name = "TG_REQUEST")
public class TgRequest {
@Id
@SequenceGenerator(name = "TG_REQUEST", sequenceName = "S_TG_REQUEST", allocationSize = 1)
@GeneratedValue(generator = "TG_REQUEST")
@Getter
@Setter
private Long idRequest;
@OneToMany(mappedBy = "tgRequest", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
@Getter
@Setter
private Set<TgRequestPerson> tgRequestPersons = new HashSet<>();
public TgRequest() {
}
public void addTgRequestPerson(TgRequestPerson tgRequestPerson) {
tgRequestPersons.add(tgRequestPerson);
tgRequestPerson.setTgRequest(this);
}
public void removeTgRequestPerson(TgRequestPerson tgRequestPerson) {
this.tgRequestPersons.remove(tgRequestPerson);
tgRequestPerson.setTgRequest(null);
}
}
@Entity
@Table(name = "TG_PERSON")
public class TgPerson {
@Id
@SequenceGenerator(name = "TG_PERSON", sequenceName = "S_TG_PERSON", allocationSize = 1)
@GeneratedValue(generator = "TG_PERSON")
@Getter
@Setter
private Long idPerson;
@OneToMany(mappedBy = "tgPerson")
@Getter
@Setter
private Set<TgRequestPerson> tgRequestPersons = new HashSet<>();
public TgPerson() {
}
public void addTgRequestPerson(TgRequestPerson tgRequestPerson) {
tgRequestPersons.add(tgRequestPerson);
tgRequestPerson.setTgPerson(this);
}
public void removeTgRequestPerson(TgRequestPerson tgRequestPerson) {
this.tgRequestPersons.remove(tgRequestPerson);
tgRequestPerson.setTgPerson(null);
}
}
@Entity
@Table(name = "TG_REQUEST_PERSON")
public class TgRequestPerson {
@EmbeddedId
@Getter
@Setter
private TgRequestPersonKey idRequestPerson;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("idRequest")
@JoinColumn(name = "ID_REQUEST")
@Getter
@Setter
private TgRequest tgRequest;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("idPerson")
@JoinColumn(name = "ID_PERSON")
@Getter
@Setter
private TgPerson tgPerson;
public TgRequestPerson() {
}
}
@Embeddable
public class TgRequestPersonKey implements Serializable {
@Column(name = "ID_REQUEST")
private Long idRequest;
@Column(name = "ID_PERSON")
private Long idPerson;
public TgRequestPersonKey() {
}
public Long getIdRequest() {
return idRequest;
}
public void setIdRequest(Long idRequest) {
this.idRequest = idRequest;
}
public Long getIdPerson() {
return idPerson;
}
public void setIdPerson(Long idPerson) {
this.idPerson = idPerson;
}
}
要保存的代码(新请求 link 到 db 上的现有人员):
TgRequest tgRequest = new TgRequest();
Long idPerson = 1; //Person already exists on db, with id = 1
TgPerson tgPerson = new TgPerson();
tgPerson.setIdPerson(idPerson)
TgRequestPerson tgRequestPerson = new TgRequestPerson();
TgRequestPersonKey tgRequestPersonKey = new TgRequestPersonKey();
tgRequestPersonKey.setIdRequest(tgRequest.getIdRequest());
tgRequestPersonKey.setIdPerson(idPerson);
tgRequest.addTgRequestPerson(tgRequestPerson);
tgPerson.addTgRequestPerson(tgRequestPerson);
tgRequestPerson.setIdRequestPerson(tgRequestPersonKey);
requestRepository.save(tgRequest);
我在看什么
插入tgRequest; --> 生成一个新的 id
插入 tgRequestPerson(idRequest = 新创建,idPerson = 1) (link 数据库上已经有人的新创建请求)
失败了。
错误
org.hibernate.PersistentObjectException: detached entity passed to persist: TgPerson
要更新的代码(link 一个创建的请求和一个创建的人)
TgRequest tgRequest = requestRepository.findByIdRequest(1); //Request already exists
Long idPerson = 1; //Person already exists on db, with id = 1,
TgPerson tgPerson = new TgPerson();
tgPerson.setIdPerson(idPerson)
TgRequestPerson tgRequestPerson = new TgRequestPerson();
TgRequestPersonKey tgRequestPersonKey = new TgRequestPersonKey();
tgRequestPersonKey.setIdRequest(tgRequest.getIdRequest());
tgRequestPersonKey.setIdPerson(idPerson);
tgRequest.addTgRequestPerson(tgRequestPerson);
tgPerson.addTgRequestPerson(tgRequestPerson);
tgRequestPerson.setIdRequestPerson(tgRequestPersonKey);
requestRepository.save(tgRequest);
期待中
插入 tgRequestPerson(idRequest = 1,idPerson = 1)有效!
那么,我怎样才能使保存代码生效?
错误发生是因为设置了对象的(tgPerson)ID。 Hibernate 区分瞬态对象和分离对象,save
仅适用于瞬态对象。如果 save
断定对象已分离(因为设置了 ID,它会分离),它将 return 出现“已分离的对象传递给持久化”错误。您可以找到更多详细信息 here and here.
但是,这仅适用于您已指定要自动生成主键的情况:如果该字段配置为始终手动设置,则您的代码有效。
所以你需要删除那些注释
@SequenceGenerator(name = "TG_PERSON", sequenceName = "S_TG_PERSON", allocationSize = 1)
@GeneratedValue(generator = "TG_PERSON")
或者调用saveOrUpdate方法
您将不得不使用 getOne
,它在幕后使用 entityManager.getReference
来引用现有对象。
TgRequest tgRequest = requestRepository.findByIdRequest(1); //Request already exists
Long idPerson = 1; //Person already exists on db, with id = 1,
TgPerson tgPerson = personRepository.getOne(idPerson);
TgRequestPerson tgRequestPerson = new TgRequestPerson();
TgRequestPersonKey tgRequestPersonKey = new TgRequestPersonKey();
tgRequestPersonKey.setIdRequest(tgRequest.getIdRequest());
tgRequestPersonKey.setIdPerson(idPerson);
tgRequest.addTgRequestPerson(tgRequestPerson);
tgPerson.addTgRequestPerson(tgRequestPerson);
tgRequestPerson.setIdRequestPerson(tgRequestPersonKey);
requestRepository.save(tgRequest);