2

我在父子关系中有两个类,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);

我得到以下生成的 SQL 和 Oracle 本机异常。生成的 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 没问题,但第二个生成的 sql 仍然是错误的,尽管它与前一个有点不同。

提前感谢您的麻烦。

4

1 回答 1

0

I've added attribute inverse="true" in the bag mapping, and no more errors occurred.

<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>

I'm quoting the following from the book "Java Persistence with Hibernate, p266".

Without the inverse attribute, Hibernate tries to execute two different SQL statements, both updating the same foreign key column, when you manipulate the link between two instances. By specifying inverse="true", you explicitly tell Hibernate which end of the link it should not synchronize with the database. In this example, you tell Hibernate that it should propagate changes made at the (ElwUnderlyingAsset) end of the association to the database, ignoring changes made only to the (underlyingAssetList) collection.

于 2012-09-05T10:49:43.317 回答