对象引用了一个未保存的瞬态实例-在刷新之前保存该瞬态实例-StreetAddress和SourceStreetAddress

问题描述

我有两个实体类StreetAddress,另一个是sourceStreetAddress,它们通过OnetoOne映射关联,如下所示。

街道地址

@Entity
@Table(name = "T_STREET_ADDRESS")
@discriminatorValue(value = "STRT")
@PrimaryKeyJoinColumn(name = "STREET_ADDRESS_ID")
public class StreetAddress extends Address implements AuditableLevelTwo,Serializable {
    private static final long serialVersionUID = 409694762467210951L;
    @Column(name = "ADDRESS_LINE_1_TXT",length = 240)
    private String addressLine1Text;
    @Column(name = "ADDRESS_LINE_2_TXT",length = 240)
    private String addressLine2Text;
    @Transient
    private String addressLine3Text;
    @Column(name = "CARRIER_ROUTE_TXT")
    private String carrierRouteText;
    @Column(name = "CITY_NM",length = 100)
    private String cityName;
    @Column(name = "CLEAN_ADDRESS_IND",nullable = true,length = 1)
    private String cleanAddressIndicator;
    @Column(name = "COUNTRY_CD",length = 3)
    private String countryCode;
    @Column(name = "DATA_SOURCE_TYPE_CD")
    private String dataSourceType;
    @Column(name = "FULL_POSTAL_CODE_TXT",length = 20,unique = false)
    private String fullPostalCodeText;
    @Embedded
    private Audit levelTwoAudit;
    @OnetoOne(fetch = FetchType.EAGER,mappedBy = "streetAddress",cascade = CascadeType.ALL)
    private ServiceAddress serviceAddress;
    @Column(name = "SERVICE_ADDRESS_FLAG",length = 1)
    private String serviceAddressFlag;
    @OnetoOne(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
    private SourceStreetAddress sourceStreetAddress;
    @OnetoMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL,mappedBy = "streetAddress")
    @Fetch(FetchMode.SELECT)
    private Set<StreetAddressServicability> streetAddressServicability = new HashSet<StreetAddressServicability>();
    @Column(name = "TERRITORY_CD",length = 2)
    private String territoryCode;
    @Column(name = "VALID_ADDRESS_IND",length = 1)
    private String validAddressIndicator;
    @Column(name = "ZIP4",insertable = false,updatable = false)
    private String ZIP4;
    @Column(name = "ZIP5",updatable = false)
    private String ZIP5;

    public StreetAddress() {
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (getClass() != obj.getClass())
            return false;
        StreetAddress other = (StreetAddress) obj;
        if (addressLine1Text == null) {
            if (other.addressLine1Text != null)
                return false;
        } else if (!addressLine1Text.equals(other.addressLine1Text))
            return false;
        if (addressLine2Text == null) {
            if (other.addressLine2Text != null)
                return false;
        } else if (!addressLine2Text.equals(other.addressLine2Text))
            return false;
        if (cityName == null) {
            if (other.cityName != null)
                return false;
        } else if (!cityName.equals(other.cityName))
            return false;
        if (fullPostalCodeText == null || fullPostalCodeText.trim().equals("") || fullPostalCodeText.trim().length() < 5) {
            if (other.fullPostalCodeText != null)
                return false;
        } else if (!fullPostalCodeText.replace("-","").substring(0,5)
                .equals(other.fullPostalCodeText != null && other.fullPostalCodeText.replace("-","").length() >= 5 ? other.fullPostalCodeText.replace("-",5) : ""))
            return false;
        if (territoryCode == null) {
            if (other.territoryCode != null)
                return false;
        } else if (!territoryCode.equals(other.territoryCode))
            return false;
        return true;
    }

    // getter and setter
}

SourceStreetAddress

@Entity
@Table(name = "T_SOURCE_STREET_ADDRESS")
public class SourceStreetAddress extends AbstractSequencedModelObject<Long> {
    private static final long serialVersionUID = 409694762467210951L;
    @Column(name = "ADDRESS_LINE_1_TXT",length = 240)
    private String addressLine2Text;
    @Embedded
    private Audit audit;
    @Column(name = "CITY_NM",length = 100)
    private String cityName;
    @Column(name = "COUNTRY_CD",length = 100)
    private String countryCode;
    @Column(name = "POSTAL_CODE_TXT",length = 100)
    private String fullPostalCodeText;
    @Id
    @Column(name = "SOURCE_STREET_ADDRESS_ID",length = 19,nullable = false)
    private Long id;
    @MapsId
    @OnetoOne(fetch = FetchType.EAGER,optional = true)
    @JoinColumn(name = "SOURCE_STREET_ADDRESS_ID",referencedColumnName = "STREET_ADDRESS_ID",nullable = false,unique = false,insertable = true,updatable = true)
    private StreetAddress streetAddress;
    @Column(name = "TERRITORY_CD",length = 100)
    private String territoryCode;

   // getter and setter
}

所以当我第一次测试它时,我在下面遇到了异常

A different object with the same identifier value was already associated with the session : [com.charter.enterprise.domain.sourceStreetAddress#80023962]A different object with the same identifier value was already associated with the session : [com.charter.enterprise.domain.sourceStreetAddress#80023962]   

但是我读过某处,这个异常表明Hibernate试图插入一个已经存在的实体(SourceStreetAddress实体)。可能是因为 Cascade.ALL代表StreetAddress内的SourceStreetAddress属性

因此我将其更改为CascadeType.MERGE,希望它会首先检查SourceStreetAddress实体是否存在,然后尝试插入,否则它将只进行更新。

@OnetoOne(fetch = FetchType.EAGER,cascade = CascadeType.MERGE)
    private SourceStreetAddress sourceStreetAddress;

但是现在我在下面遇到了异常:

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.charter.enterprise.domain.StreetAddress.sourceStreetAddress -> com.charter.enterprise.domain.sourceStreetAddress;

我已经面对这个问题已经有一段时间了。 请任何人帮助我如何解决它以及这里出了什么问题。

要保存对象并引发异常的代码部分

public StreetAddress createAddress(StreetAddress streetAddress,String dataSourceTypeCode,String transactionId) throws RuntimeException {
        logger.info("transactionId: " + transactionId + " createAddress is called");
        Locator locator = new Locator();
        locator.setLocatorSubTypeCode(STREET_ADDRESS);
        streetAddress.setDataSourceType(dataSourceTypeCode);
        streetAddress.setServiceAddressFlag("1");
        streetAddress.setCleanAddressIndicator("0");
        // ConvertStringtoupperCase.toupperCase(streetAddress);
        if (streetAddress.getServiceAddress() == null) {
            throw new RuntimeException("Service address should not be null");
        }
        ServiceAddress serviceAddressFromrequest = streetAddress.getServiceAddress();
        
        Set<AddressMemo> reqAddressMemos = null;
        if (!streetAddress.getAddressMemo().isEmpty()) {
            reqAddressMemos = streetAddress.getAddressMemo();
            streetAddress.setAddressMemo(null);
        }
        if (serviceAddressFromrequest.getRateCenter() != null && serviceAddressFromrequest.getRateCenter().getLocationName() != null
                && !serviceAddressFromrequest.getRateCenter().getLocationName().isEmpty()) {
            String locationName = serviceAddressFromrequest.getRateCenter().getLocationName();
            Location location = findCreateLocation(locationName,dataSourceTypeCode);
            serviceAddressFromrequest.setRateCenter(location);
        } else {
            serviceAddressFromrequest.setRateCenter(null);
        }
        streetAddress = addressServiceImpl.cleanSpacesInStreetAddress(streetAddress);
        SourceStreetAddress sourceStreetAddress = new SourceStreetAddress();
        sourceStreetAddress.setStreetAddress(streetAddress);
        sourceStreetAddress.setAddressLine1Text(streetAddress.getAddressLine1Text());
        sourceStreetAddress.setAddressLine2Text(streetAddress.getAddressLine2Text());
        sourceStreetAddress.setCityName(streetAddress.getCityName());
        sourceStreetAddress.setCountryCode(streetAddress.getCountryCode());
        sourceStreetAddress.setFullPostalCodeText(streetAddress.getFullPostalCodeText());
        sourceStreetAddress.setTerritoryCode(streetAddress.getTerritoryCode());
        // moved scrubbing down so that sourceStreetAddress table can have raw data.
        streetAddress = addressServiceImpl.scrubStreetAddress(streetAddress,transactionId);
        streetAddress.setSourceStreetAddress(sourceStreetAddress);
        // streetAddress.setDataSourceType(dataSourceTypeCode);
        streetAddress.setLocator(locator);
        // serviceAddressFromrequest.setSourceSystemId(streetAddress.getSourceSystemAddressId());
        serviceAddressFromrequest.setStreetAddress(streetAddress);
        serviceAddressFromrequest.setDataSourceType(dataSourceTypeCode);
        // CESCHTRENT-7890
        if (null != serviceAddressFromrequest.getServiceAddressOffers() && !serviceAddressFromrequest.getServiceAddressOffers().isEmpty()) {
            for (ServiceAddressOffer serviceAddressOffer : serviceAddressFromrequest.getServiceAddressOffers()) {
                serviceAddressOffer.setServiceAddress(serviceAddressFromrequest);
            }
        }
        streetAddress.setServiceAddress(serviceAddressFromrequest);
        if (!streetAddress.getStreetAddressServicability().isEmpty())
            for (StreetAddressServicability streetAddressServicability : streetAddress.getStreetAddressServicability()) {
                // streetAddressServicability.setAudit(audit);
                // ConvertStringtoupperCase.toupperCase(streetAddressServicability);
                streetAddressServicability.setDataSourceTypeCode(dataSourceTypeCode);
                streetAddressServicability.setStreetAddress(streetAddress);
                if (serviceAddressFromrequest.getSourceFta() != null && serviceAddressFromrequest.getSourceFta().getBillingStation() != null
                        && serviceAddressFromrequest.getSourceFta().getBillingStation().getId() != null && streetAddressServicability.getHeadEnd() != null
                        && !StringUtils.isEmpty(streetAddressServicability.getHeadEnd().getHeadendCode())) {
                    Headend dbHeadend = findCreateHeadend(streetAddressServicability.getHeadEnd().getHeadendCode(),serviceAddressFromrequest.getSourceFta().getBillingStation().getId(),dataSourceTypeCode);
                    streetAddressServicability.setHeadEnd(dbHeadend);
                } else {
                    streetAddressServicability.setHeadEnd(null);
                }
            }
        if (!CollectionUtils.isEmpty(reqAddressMemos)) {
            Set<AddressMemo> addressMemos = new HashSet<>();
            for (AddressMemo addressMemo : reqAddressMemos) {
                addressMemo.setAddress(streetAddress);
                Memo memo = addressMemo.getMemo();
                if (null != memo) {
                    memo.setMemoTypeCode("ADDR");
                    memo.setMemoSequenceNumber(1l);
                    memo = memoRepository.save(memo);
                }
                if (addressMemo.getSourceSystemAddressMemoId() == null || addressMemo.getSourceSystemAddressMemoId().trim().isEmpty()) {
                    addressMemo.setSourceSystemAddressMemoId(memo.getMemoId().toString());
                }
                addressMemo.setMemo(memo);
                addressMemos.add(addressMemo);
            }
            // addressMemoRepository.save(addressMemos);
            streetAddress.setAddressMemo(addressMemos);
        }
        StreetAddress streetAddressSaved = addressRepository.save(streetAddress);
        
      
        return streetAddressSaved;
    }

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)