如何解决双向映射休眠不会在两个相关实体上自动更新
我正在使用javaFx
和Spring-Boot
创建Hibernate
应用程序,当我要保存其中包含其他实体列表的实体时遇到问题。
数据库结构:
CREATE TABLE IF NOT EXISTS AR_LANDLORD (
AR_LANDLORD_ID INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,FIRST_NAME VARCHAR(255) NOT NULL,SURNAME VARCHAR(255) NOT NULL,LAST_NAME VARCHAR(255) NOT NULL,PIN NUMERIC NOT NULL,SETTLEMENT VARCHAR(255) NOT NULL,ADDRESS VARCHAR(255) NOT NULL,ADDRESS_NUMBER NUMERIC NOT NULL
);
CREATE TABLE IF NOT EXISTS AR_LANDLORD_PROPERTY(
AR_LAND_PROPERTY_ID INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL,LAND VARCHAR(255) NOT NULL,LOCALITY VARCHAR(255)NOT NULL,EKATTE NUMERIC NOT NULL,CADASTRE_NUMBER VARCHAR(255) NOT NULL,PROPERTY_NUMBER NUMERIC NOT NULL,AREA FLOAT NOT NULL,AR_LANDLORD_ID INTEGER,foreign key (AR_LANDLORD_ID) references AR_LANDLORD(AR_LANDLORD_ID)
);
DTOS:
地主:
public class LandLord {
private Long id;
private String firstName;
private String surname;
private String lastName;
private Long PIN;
private String settlement;
private String address;
private Long addressNumber;
private List<LandLordProperty> landLordProperties;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Long getPIN() {
return PIN;
}
public void setPIN(Long PIN) {
this.PIN = PIN;
}
public String getSettlement() {
return settlement;
}
public void setSettlement(String settlement) {
this.settlement = settlement;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Long getAddressNumber() {
return addressNumber;
}
public void setAddressNumber(Long addressNumber) {
this.addressNumber = addressNumber;
}
public List<LandLordProperty> getLandLordProperties() {
return landLordProperties;
}
public void setLandLordProperties(List<LandLordProperty> landLordProperties) {
this.landLordProperties = landLordProperties;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof LandLord)) return false;
LandLord landLord = (LandLord) o;
return getId().equals(landLord.getId());
}
@Override
public int hashCode() {
return Objects.hash(getId());
}
}
LandLordProperty :
public class LandLordProperty {
private Long id;
private String land;
private String locality;
private Long ekatte;
private String cadastreNumber;
private Long propertyNumber;
private Float area;
private Long landLordId;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLand() {
return land;
}
public void setLand(String land) {
this.land = land;
}
public String getLocality() {
return locality;
}
public void setLocality(String locality) {
this.locality = locality;
}
public Long getEkatte() {
return ekatte;
}
public void setEkatte(Long ekatte) {
this.ekatte = ekatte;
}
public String getCadastreNumber() {
return cadastreNumber;
}
public void setCadastreNumber(String cadastreNumber) {
this.cadastreNumber = cadastreNumber;
}
public Long getPropertyNumber() {
return propertyNumber;
}
public void setPropertyNumber(Long propertyNumber) {
this.propertyNumber = propertyNumber;
}
public Float getArea() {
return area;
}
public void setArea(Float area) {
this.area = area;
}
public Long getLandLordId() {
return landLordId;
}
public void setLandLordId(Long landLordId) {
this.landLordId = landLordId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof LandLordProperty)) return false;
LandLordProperty that = (LandLordProperty) o;
return getId().equals(that.getId());
}
@Override
public int hashCode() {
return Objects.hash(getId());
}
}
实体:
LandLordEntity
@Entity
@Table(name = "AR_LANDLORD")
public class LandLordEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "AR_LANDLORD_ID")
private Long id;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "SURNAME")
private String surname;
@Column(name = "LAST_NAME")
private String lastName;
@Column(name = "PIN")
private Long PIN;
@Column(name = "SETTLEMENT")
private String settlement;
@Column(name = "ADDRESS")
private String address;
@Column(name = "ADDRESS_NUMBER")
private Long addressNumber;
@OneToMany(fetch = FetchType.EAGER,orphanRemoval = true,mappedBy = "landLord",cascade = CascadeType.ALL)
private List<LandLordPropertyEntity> landLordProperties = new ArrayList<>();
public LandLordEntity(){}
public LandLordEntity(Long id){
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Long getPIN() {
return PIN;
}
public void setPIN(Long PIN) {
this.PIN = PIN;
}
public String getSettlement() {
return settlement;
}
public void setSettlement(String settlement) {
this.settlement = settlement;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Long getAddressNumber() {
return addressNumber;
}
public void setAddressNumber(Long addressNumber) {
this.addressNumber = addressNumber;
}
public List<LandLordPropertyEntity> getLandLordProperties() {
return landLordProperties;
}
public void setLandLordProperties(List<LandLordPropertyEntity> landLordProperties) {
this.landLordProperties = landLordProperties;
}
public static LandLord convertToDto(LandLordEntity entity) {
LandLord dto = new LandLord();
dto.setId(entity.getId());
dto.setFirstName(entity.getFirstName());
dto.setSurname(entity.getSurname());
dto.setLastName(entity.getLastName());
dto.setPIN(entity.getPIN());
dto.setAddress(entity.getAddress());
dto.setAddressNumber(entity.getAddressNumber());
dto.setSettlement(entity.getSettlement());
final List<LandLordPropertyEntity> landLordProperties = entity.getLandLordProperties();
if (CollectionUtils.isNotEmpty(landLordProperties)) {
dto.setLandLordProperties(landLordProperties.stream()
.map(LandLordPropertyEntity::convertToDto)
.collect(Collectors.toList()));
}
return dto;
}
public static LandLordEntity convertToEntity(LandLord dto) {
LandLordEntity entity = new LandLordEntity();
entity.setId(dto.getId());
entity.setFirstName(dto.getFirstName());
entity.setSurname(dto.getSurname());
entity.setLastName(dto.getLastName());
entity.setPIN(dto.getPIN());
entity.setAddress(dto.getAddress());
entity.setAddressNumber(dto.getAddressNumber());
entity.setSettlement(dto.getSettlement());
final List<LandLordProperty> landLordProperties = dto.getLandLordProperties();
if (CollectionUtils.isNotEmpty(landLordProperties)) {
entity.setLandLordProperties(landLordProperties.stream()
.map(LandLordPropertyEntity::convertToEntity)
.collect(Collectors.toList()));
}
return entity;
}
}
LandLordPropertyEntity
@Entity
@Table(name = "AR_LANDLORD_PROPERTY")
public class LandLordPropertyEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "AR_LAND_PROPERTY_ID")
private Long id;
@Column(name = "LAND")
private String land;
@Column(name = "LOCALITY")
private String locality;
@Column(name = "EKATTE")
private Long ekatte;
@Column(name = "CADASTRE_NUMBER")
private String cadastreNumber;
@Column(name = "PROPERTY_NUMBER")
private Long propertyNumber;
@Column(name = "AREA")
private Float area;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "AR_LANDLORD_ID")
private LandLordEntity landLord;
public LandLordPropertyEntity(){}
public LandLordPropertyEntity(Long id){
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLand() {
return land;
}
public void setLand(String land) {
this.land = land;
}
public String getLocality() {
return locality;
}
public void setLocality(String locality) {
this.locality = locality;
}
public Long getEkatte() {
return ekatte;
}
public void setEkatte(Long ekatte) {
this.ekatte = ekatte;
}
public String getCadastreNumber() {
return cadastreNumber;
}
public void setCadastreNumber(String cadastreNumber) {
this.cadastreNumber = cadastreNumber;
}
public Long getPropertyNumber() {
return propertyNumber;
}
public void setPropertyNumber(Long propertyNumber) {
this.propertyNumber = propertyNumber;
}
public Float getArea() {
return area;
}
public void setArea(Float area) {
this.area = area;
}
public LandLordEntity getLandLord() {
return landLord;
}
public void setLandLord(LandLordEntity landLord) {
this.landLord = landLord;
}
public static LandLordProperty convertToDto(LandLordPropertyEntity entity) {
LandLordProperty dto = new LandLordProperty();
dto.setId(entity.getId());
dto.setLand(entity.getLand());
dto.setLocality(entity.getLocality());
dto.setEkatte(entity.getEkatte());
dto.setCadastreNumber(entity.getCadastreNumber());
dto.setPropertyNumber(entity.getPropertyNumber());
dto.setArea(entity.getArea());
dto.setLandLordId(entity.getLandLord() != null ? entity.getLandLord().getId() : null);
return dto;
}
public static LandLordPropertyEntity convertToEntity(LandLordProperty dto) {
LandLordPropertyEntity entity = new LandLordPropertyEntity();
entity.setId(dto.getId());
entity.setLand(dto.getLand());
entity.setLocality(dto.getLocality());
entity.setEkatte(dto.getEkatte());
entity.setCadastreNumber(dto.getCadastreNumber());
entity.setPropertyNumber(dto.getPropertyNumber());
entity.setArea(dto.getArea());
entity.setLandLord(new LandLordEntity(dto.getLandLordId()));
return entity;
}
}
服务创建方法
public Long create(LandLord landLord) {
final LandLordEntity landLordEntity = landLordRepository.save(LandLordEntity.convertToEntity(landLord));
return landLordEntity.getId();
}
这是可执行代码
LandLord landLord = new LandLord();
landLord.setFirstName("Dimitar");
landLord.setSurname("Dimitrov");
landLord.setLastName("Dimitrov");
landLord.setPIN(555555L);
landLord.setSettlement("Pz");
landLord.setAddress("street Pz Pz");
landLord.setAddressNumber(55L);
List<LandLordProperty> landLordProperties = new ArrayList<>();
LandLordProperty landLordProperty = new LandLordProperty();
landLordProperty.setArea(54F);
landLordProperty.setCadastreNumber("11.11.34");
landLordProperty.setEkatte(5444L);
landLordProperty.setLocality("Test locality");
landLordProperty.setLand("Test land");
landLordProperty.setPropertyNumber(544L);
landLordProperties.add(landLordProperty);
landLord.setLandLordProperties(landLordProperties);
landLordService.create(landLord);
请注意,有一些convert方法可以将实体从dto转换为dto。所以首先我在创建LandLord时遇到一个问题,它具有以下异常:
**Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : bg.gtechnology.agriculturerent.service.impl.model.LandLordPropertyEntity.landLord -> bg.gtechnology.agriculturerent.service.impl.model.LandLordEntity**
但是当我将cascade = CascadeType.ALL
放在LandLordPropertyEntity的LandLordEntity字段中时,如下所示:
@ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
@JoinColumn(name = "AR_LANDLORD_ID")
private LandLordEntity landLord;
问题消失了,我还有另一个问题,它创建了两次实体。首先,我有一个空List<LandLordProperty>
,第二个保存是让正确的List<LandLordProperty>
持久保存正确的数据但它会再次创建一个对象LandLord,除属性列表外,其他所有地方都具有空值。因此,我认为不必添加此批注,并且我认为问题出在其他地方。我也注意到了这一点:
public static LandLordPropertyEntity convertToEntity(LandLordProperty dto)
当我删除entity.setLandLord(new LandLordEntity(dto.getLandLordId()));
时,问题消失了,但我的列表为空。
因此,我在创建List<LandLordProperty>
的LandLord对象时也要进行双向映射,而LandLordProperty对象中的landLordId也要自动保留。你能帮我吗?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。