子对象的生成更新sql在一对多关系中不正确

时间:2012-09-04 05:59:05

标签: java spring hibernate

我在亲子关系中有两个类ElwInfo和ElwUnderlyingAsset。表名为ELW_INFO,ELW_UNDERLYING_ASSET,ELW_UNDERLYING_ASSET按列INSTRUMENT_CD引用ELW_INFO。

我已将文件'Elw.hbm.xml'中的两个类映射如下

<class name="ElwInfo" table="ELW_INFO" >

    <id name="instrumentCode" column="INSTRUMENT_CD" ><generator class="assigned"/></id>
    <property name="instrumentName" column="INSTRUMENT_NM"/>
    <property name="ccyCode"        column="CCY_CD"/>

    <one-to-one name="instrumentCommon" 
                class="InstrumentCommon"
                cascade="save-update" lazy="false" />

    <one-to-one name="instrumentClass" 
                class="InstrumentClass"
                cascade="none" lazy="false" />

    <property name="issueDate"      column="ISSUE_DT"/>
    <property name="maturityDate"   column="MRTY_DT"/>
    <property name="convertRatio"   column="CONVERT_RATIO"/>
    <property name="strike"         column="STRIKE"/>
    <property name="koBarrier"      column="KO_BARRIER"/>
    <property name="minRebateRate"  column="MIN_REBATE_RT"/>
    <property name="addRebate"      column="ADD_REBATE"/>

    <many-to-one class="com.fistglobal.riskcraft.market.web.domain.instrument2.common.ExchangeInfo" 
                 name="exchangeInfo" column="EXCH_CD" lazy="false" cascade="none" 
                 unique="true" />
    <many-to-one class="com.fistglobal.riskcraft.market.web.domain.instrument2.common.ElwTypeInfo" 
                 name="elwType" column="ELW_TYPE_CD" lazy="false" cascade="none" 
                 unique="true" />
    <many-to-one class="com.fistglobal.riskcraft.market.web.domain.instrument2.common.OptionTypeInfo" 
                 name="optionType" column="OPTION_TYPE_CD" lazy="false" cascade="none" 
                 unique="true" />
    <many-to-one class="com.fistglobal.riskcraft.market.web.domain.instrument2.common.ExerciseTypeInfo" 
                 name="exerciseType" column="EXERCISE_TYPE_CD" lazy="false" cascade="none" 
                 unique="true" />

    **<bag name="underlyingAssetList" cascade="save-update" table="ELW_UNDERLYING_ASSET" lazy="false" >
        <key column="INSTRUMENT_CD"/>
        <one-to-many class="ElwUnderlyingAsset" not-found="ignore"/>
    </bag>**

</class>

<class name="ElwUnderlyingAsset" table="ELW_UNDERLYING_ASSET" >
    <composite-id name="id" class="ElwUnderlyingAsset$Id">
        <key-property name="instrumentCode" column="INSTRUMENT_CD"/>
        <key-property name="underlyingAssetCode" column="UNDERLYING_ASSET_CD"/>
        <generator class="assigned"/>
    </composite-id>

    <property name="qty"   column="UNDERLYING_ASSET_QTY"/>
</class>

<class name="ElwData" table="ELW_DATA">
    <composite-id name="key" class="InstrumentDataKey">
        <key-property name="dt"             column="DT"/>
        <key-property name="instrumentCode" column="INSTRUMENT_CD"/>
    </composite-id>
    <property name="barrierHitYn"   column="BARRIER_HIT_YN"/>
    <property name="barrierHitDate" column="BARRIER_HIT_DT"/>
    <property name="amOrPm"         column="AM_OR_PM"/>
    <property name="maxPrice"       column="MAX_PRICE"/>
    <property name="minPrice"       column="MIN_PRICE"/>
</class>

并且两个类如下

public class ElwInfo extends InstrumentInfo {

private ExchangeInfo exchangeInfo;
private List<ElwUnderlyingAsset> underlyingAssetList;
private ElwTypeInfo elwType;
private OptionTypeInfo optionType;
private ExerciseTypeInfo exerciseType;

private String issueDate;
private String maturityDate;
private Double convertRatio;
private Double strike;
private Double koBarrier;
private Double minRebateRate;
private Double addRebate;

public ElwInfo() {
    exchangeInfo = new ExchangeInfo();
    underlyingAssetList = new ArrayList<ElwUnderlyingAsset>();
    elwType = new ElwTypeInfo();
    optionType = new OptionTypeInfo();
    exerciseType = new ExerciseTypeInfo();
}

public ExchangeInfo getExchangeInfo() {
    return exchangeInfo;
}

public void setExchangeInfo(ExchangeInfo exchangeInfo) {
    this.exchangeInfo = exchangeInfo;
}

public List<ElwUnderlyingAsset> getUnderlyingAssetList() {
    return underlyingAssetList;
}

public void setUnderlyingAssetList(List<ElwUnderlyingAsset> underlyingAssetList) {
    this.underlyingAssetList = underlyingAssetList;
}

public ElwTypeInfo getElwType() {
    return elwType;
}

public void setElwType(ElwTypeInfo elwType) {
    this.elwType = elwType;
}

public OptionTypeInfo getOptionType() {
    return optionType;
}

public void setOptionType(OptionTypeInfo optionType) {
    this.optionType = optionType;
}

public ExerciseTypeInfo getExerciseType() {
    return exerciseType;
}

public void setExerciseType(ExerciseTypeInfo execType) {
    this.exerciseType = execType;
}

public String getIssueDate() {
    return issueDate;
}

public void setIssueDate(String issueDate) {
    this.issueDate = issueDate;
}

public String getMaturityDate() {
    return maturityDate;
}

public void setMaturityDate(String maturityDate) {
    this.maturityDate = maturityDate;
}

public Double getConvertRatio() {
    return convertRatio;
}

public void setConvertRatio(Double convertRatio) {
    this.convertRatio = convertRatio;
}

public Double getStrike() {
    return strike;
}

public void setStrike(Double strike) {
    this.strike = strike;
}

public Double getKoBarrier() {
    return koBarrier;
}

public void setKoBarrier(Double koBarrier) {
    this.koBarrier = koBarrier;
}

public Double getMinRebateRate() {
    return minRebateRate;
}

public void setMinRebateRate(Double minRebateRate) {
    this.minRebateRate = minRebateRate;
}

public Double getAddRebate() {
    return addRebate;
}

public void setAddRebate(Double addRebate) {
    this.addRebate = addRebate;
}

}


public class ElwUnderlyingAsset {

public static class Id implements Serializable {

    private static final long serialVersionUID = -8296040137055492597L;

    private String instrumentCode;
    private String underlyingAssetCode;

    public String getInstrumentCode() {
        return instrumentCode;
    }
    public void setInstrumentCode(String instrumentCode) {
        this.instrumentCode = instrumentCode;
    }
    public String getUnderlyingAssetCode() {
        return underlyingAssetCode;
    }
    public void setUnderlyingAssetCode(String underlyingAssetCode) {
        this.underlyingAssetCode = underlyingAssetCode;
    }

    public boolean equals(Object o) {
        if (o != null && o instanceof Id) {
            Id that = (Id)o;
            return this.instrumentCode.equals(that.instrumentCode) && this.underlyingAssetCode.equals(that.underlyingAssetCode);
        } else {
            return false;
        }
    }

    public int hashCode() {
        if (instrumentCode!= null && underlyingAssetCode != null)
            return instrumentCode.hashCode() + underlyingAssetCode.hashCode();
        else
            return -1;
    }

    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
    }

}

public ElwUnderlyingAsset() {
    this.id = new Id();
}

private Id id;
private Double qty;

public Id getId() {
    return id;
}
public void setId(Id id) {
    this.id = id;
}

public Double getQty() {
    return qty;
}
public void setQty(Double qty) {
    this.qty = qty;
}

public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}

当我打电话

ElwInfo newInfo = .....// info instance is constructed purely from http request parameters .
getHibernateTemplate().saveOrUpdate(newInfo);

我得到以下Generated SQL和Oracle Native Exception。生成的SQL非常荒谬,我无法弄清楚我做错了什么。

Hibernate: 
update
    ELW_UNDERLYING_ASSET 
set
    INSTRUMENT_CD=null 
where
    INSTRUMENT_CD=?

我期待的是

Hibernate: 
update
    ELW_UNDERLYING_ASSET 
set
    QTY = ?
where
    INSTRUMENT_CD=?
    and UNDERLYING_ASSET_CD=?

因为表ELW_UNDERLYING_ASSET有复合键(INSTRUMENT_CD,UNDERLYING_ASSET_CD)。

如果我按如下方式修改我的客户端代码,

ElwInfo newInfo = .....// info instance is constructed purely from http request 
ElwInfo info = (ElwInfo)getHibernateTemplate().get(entityInfo.getClass(),entityInfo.getInstrumentCode());
info.setAddRebate(0.0);
info.getUnderlyingAssetList().clear();
info.getUnderlyingAssetList().addAll(newInfo.getUnderlyingAssetList());
getHibernateTemplate().saveOrUpdate(info);

我得到以下生成的SQL;

Hibernate: 
update
    ELW_INFO 
set
    INSTRUMENT_NM=?,
    CCY_CD=?,
    ISSUE_DT=?,
    MRTY_DT=?,
    CONVERT_RATIO=?,
    STRIKE=?,
    KO_BARRIER=?,
    MIN_REBATE_RT=?,
    ADD_REBATE=?,
    EXCH_CD=?,
    ELW_TYPE_CD=?,
    OPTION_TYPE_CD=?,
    EXERCISE_TYPE_CD=? 
where
    INSTRUMENT_CD=?

Hibernate: 
update
    ELW_UNDERLYING_ASSET 
set
    INSTRUMENT_CD=null 
where
    INSTRUMENT_CD=? 
    and UNDERLYING_ASSET_CD=?

第一个生成的sql是可以的,但第二个仍然是错误的,虽然它与前一个有点不同。

提前感谢您的麻烦。

1 个答案:

答案 0 :(得分:0)

我在行李贴图中添加了属性 inverse =“true”,不再发生错误。

<bag name="underlyingAssetList" inverse="true" cascade="save-update" table="ELW_UNDERLYING_ASSET" lazy="false" >
        <key column="INSTRUMENT_CD"/>
        <one-to-many class="ElwUnderlyingAsset" not-found="ignore"/>
</bag>

我引用了“Java Persistence with Hibernate,p266”一书中的以下内容。

  

没有inverse属性,Hibernate会尝试执行两个   不同的SQL语句,都更新相同的外键列,   当您操纵两个实例之间的链接时。通过指定   inverse =“true”,你明确告诉Hibernate链接的哪一端   它不应该与数据库同步。在这个例子中,你   告诉Hibernate它应该传播在   (ElwUnderlyingAsset)结束与数据库的关联,忽略   仅对(underlyingAssetList)集合进行了更改。