Java 使用JPA1.0注释派生的复合键(复合键多对一)

Java 使用JPA1.0注释派生的复合键(复合键多对一),java,hibernate,jpa,annotations,Java,Hibernate,Jpa,Annotations,我有一个简单的关系,如上图所示 我可以使用以下Hibernate映射来保持这一点: <class name="Strategy" table="Strategy"> <id name="id" column="StrategyId" unsaved-value="any"> <generator class="identity"/> </id> <property name="status" colum

我有一个简单的关系,如上图所示

我可以使用以下Hibernate映射来保持这一点:

<class name="Strategy" table="Strategy">
    <id name="id" column="StrategyId" unsaved-value="any">
        <generator class="identity"/>
    </id>
    <property name="status" column="Status"/>
</class>

<class name="Alert" table="Alert">
    <id name="id" column="AlertId">
        <generator class="identity"/>
    </id>
    <property name="name" column="Name"/>        
</class>

<class name="StrategyAlert" table="StrategyAlert">
    <composite-id>            
        <key-many-to-one name="strategy" class="Strategy" column="StrategyId"/>
        <key-many-to-one name="alert" class="Alert" column="AlertId"/>
    </composite-id>
    <property name="nominal" column="Nominal"/>
</class>
策略类:

@Entity
@Table(name="STRATEGY")
public class Strategy implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)    
    @Column(name="STRATEGYID")
    private int id;

    @Column(name="STATUS")
    private String status;
}
StrategyAlertPK类:

public class StrategyAlertPK implements Serializable {

    private int strategyId;
    private int alertId;
}
StrategyAlert类:

@Entity
@Table(name="STRATEGYALERT")
@IdClass(StrategyAlertPK.class)
public class StrategyAlert implements Serializable {

    @Id
    @Column(name="STRATEGYID")
    private int strategyId;

    @Id
    @Column(name="ALERTID")
    private int alertId;

    @ManyToOne
    @JoinColumn(name="STRATEGYID", insertable=false, updatable=false)
    private Strategy strategy;

    @ManyToOne
    @JoinColumn(name="ALERTID", insertable=false, updatable=false)
    private Alert alert;

    @Column
    private String nominal;
}
测试用例:

em.getTransaction().begin();       
Alert alert = new Alert();
alert.setName("NAME");
em.persist(alert);

Strategy strategy = new Strategy();
strategy.setStatus("STATUS");        
em.persist(strategy);

StrategyAlert strategyAlert = new StrategyAlert();
strategyAlert.setAlert(alert);
strategyAlert.setStrategy(strategy);
strategyAlert.setNominal("NOMINAL");
em.persist(strategyAlert);        
em.getTransaction().commit();      
我得到以下错误:

引用完整性约束冲突:“FK80432DA9CE00672E:PUBLIC.STRATEGYALERT外键(STRATEGYID)引用PUBLIC.STRATEGY(STRATEGYID)(0)

我正在使用
生成表


如何正确注释StrategyAlert类?

查看以下问题:

我认为这里的问题是您必须加入JPA1中描述的Id声明和多通声明,我现在无法测试代码,但或多或少它必须是这样

@Entity
@Table(name="STRATEGYALERT")
@IdClass(StrategyAlertPK.class)
public class StrategyAlert implements Serializable {
   @Id
   @ManyToOne
   @JoinColumn(name="STRATEGYID", insertable=false, updatable=false)
   private Strategy strategy;

   @Id
   @ManyToOne
   @JoinColumn(name="ALERTID", insertable=false, updatable=false)
   private Alert alert;

   @Column
   private String nominal;

   // TODO Getters and setters
}
更新

现在我可以测试代码了,正在为m编写以下代码(一些修正):

策略

/**
 * 
 */
package hib;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 *
 */
@Entity
@Table(name="STRATEGY")
public class Strategy implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)    
    @Column(name="STRATEGYID")
    private int id;

    @Column(name="STATUS")
    private String status;

    /**
     * @return the id
     */
    public int getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * @return the status
     */
    public String getStatus() {
        return status;
    }

    /**
     * @param status the status to set
     */
    public void setStatus(String status) {
        this.status = status;
    }
}
战略警报PK

/**
 * 
 */
package hib;

import java.io.Serializable;

import javax.persistence.Embeddable;

/**
 *
 */
@Embeddable
public class StrategyAlertPK implements Serializable {

    @ManyToOne
    private Strategy strategy;

    @ManyToOne
    private Alert alert;
    /**
     * @return the strategy
     */
    public Strategy getStrategy() {
        return strategy;
    }
    /**
     * @param strategy the strategy to set
     */
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    /**
     * @return the alert
     */
    public Alert getAlert() {
        return alert;
    }
    /**
     * @param alert the alert to set
     */
    public void setAlert(Alert alert) {
        this.alert = alert;
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        StrategyAlertPK that = (StrategyAlertPK) o;

        if (strategy != null ? !strategy.equals(that.strategy) : that.strategy != null) {
            return false;
        }
        if (alert != null ? !alert.equals(that.alert) : that.alert != null) {
            return false;
        }

        return true;
    }

    public int hashCode() {
        int result;
        result = (strategy != null ? strategy.hashCode() : 0);
        result = 31 * result + (alert != null ? alert.hashCode() : 0);
        return result;
    }


}
战略警报

/**
 * 
 */
package hib;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 *
 */
@Entity
@Table(name="STRATEGYALERT")
    @AssociationOverrides({ @AssociationOverride(name = "pk.strategy", joinColumns = @JoinColumn(name = "STRATEGYID")),
    @AssociationOverride(name = "pk.alert", joinColumns = @JoinColumn(name = "ALERTID")) })
public class StrategyAlert implements Serializable {

    @EmbeddedId
    private StrategyAlertPK pk = new StrategyAlertPK();

    @Column
    private String nominal;

    @Transient
    public Strategy getStrategy() {
        return pk.getStrategy();
    }

    public void setStrategy(Strategy strategy) {
        pk.setStrategy(strategy);
    }

    @Transient
    public Alert getAlert() {
        return pk.getAlert();
    }

    public void setAlert(Alert alert) {
        pk.setAlert(alert);
    }

    /**
     * @return the nominal
     */
    public String getNominal() {
        return nominal;
    }

    /**
     * @param nominal the nominal to set
     */
    public void setNominal(String nominal) {
        this.nominal = nominal;
    }
}
有了这些代码,您的测试运行正常(我用JPA1.0.1、Hibernate 3.3.1.GA和spring 2.5.5对其进行了测试)。我使用H2作为内存数据库,所以我必须在生成的值中将标识更改为自动,也许您不需要这样做


希望有帮助!

我已经找到了解决办法,但我认为这不是正确的方法

我有一个用于ID的静态嵌套类。然后在两个setter方法中我也设置了ID。这似乎是一种非常手动的方法,肯定有更好的方法吗

@Entity
@Table(name="STRATEGYALERT")
public class StrategyAlert {

    @Embeddable
    public static class Id implements Serializable {
        private static final long serialVersionUID = -8270591004786497335L;

        @Column(name="STRATEGYID")
        private int strategyId;

        @Column(name="ALERTID")
        private int alertId;

        public Id() {}

        public Id(int strategyId, int alertId) {
            this.strategyId = strategyId;
            this.alertId = alertId;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + alertId;
            result = prime * result + strategyId;
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if(this == obj)
                return true;
            if(obj == null)
                return false;
            if(getClass() != obj.getClass())
                return false;
            Id other = (Id)obj;
            if(alertId != other.alertId)
                return false;
            if(strategyId != other.strategyId)
                return false;
            return true;
        }

    }    

    @EmbeddedId
    private Id id = new Id();

    @ManyToOne
    @JoinColumn(name="STRATEGYID", insertable=false, updatable=false)
    private Strategy strategy;

    @ManyToOne
    @JoinColumn(name="ALERTID", insertable=false, updatable=false)
    private Alert alert;

    @Column(name="NOMINAL")
    private String nominal;    

    public StrategyAlert() {}

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;    
        // SET ID
        this.id.strategyId = strategy.getId();
    }

    public void setAlert(Alert alert) {
        this.alert = alert;    
        // SET ID
        this.id.alertId = alert.getId();
    }

    // Other Getters & Setters...
}

感谢Francisco的帮助,我尝试了这一点,但我得到了一个Id类找不到其属性的错误:“在用@IdClass:hib.StrategyAlert注释的实体中找不到属性(alertId,strategyId)“我已经尝试了我能想到的一切,但我无法让它发挥作用。考虑到它在XML中的易用性,您会认为使用注释应该足够容易。有人知道如何让这个工作吗?嗨,我更新了我的答案,现在我可以测试代码了,正在为我工作。希望有帮助我也在使用H2。我复制/粘贴了您刚刚重命名为hib的代码包。我收到以下错误:
原因:org.hibernate.PropertyAccessException:无法通过hib.StrategyAlertPK.alert的反射设置器设置字段值
原因:java.lang.IllegalArgumentException:无法将int字段hib.StrategyAlertPK.alert设置为hib.alert
。我正在使用HIbernate v3.2.4,我可能会尝试另一个版本,因为我看不出为什么会发生这种情况。我用最新版本的HIbernate进行了尝试,我可以使用-v3.3.1.GA/Annotations 3.4.0.GA/EntityManager 3.4.0.GA,我得到了完全相同的错误:
无法将int field hib.StrategyAlertPK.alert设置为hib.alert
。我不知道下一步该怎么办
/**
 * 
 */
package hib;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 *
 */
@Entity
@Table(name="STRATEGYALERT")
    @AssociationOverrides({ @AssociationOverride(name = "pk.strategy", joinColumns = @JoinColumn(name = "STRATEGYID")),
    @AssociationOverride(name = "pk.alert", joinColumns = @JoinColumn(name = "ALERTID")) })
public class StrategyAlert implements Serializable {

    @EmbeddedId
    private StrategyAlertPK pk = new StrategyAlertPK();

    @Column
    private String nominal;

    @Transient
    public Strategy getStrategy() {
        return pk.getStrategy();
    }

    public void setStrategy(Strategy strategy) {
        pk.setStrategy(strategy);
    }

    @Transient
    public Alert getAlert() {
        return pk.getAlert();
    }

    public void setAlert(Alert alert) {
        pk.setAlert(alert);
    }

    /**
     * @return the nominal
     */
    public String getNominal() {
        return nominal;
    }

    /**
     * @param nominal the nominal to set
     */
    public void setNominal(String nominal) {
        this.nominal = nominal;
    }
}
@Entity
@Table(name="STRATEGYALERT")
public class StrategyAlert {

    @Embeddable
    public static class Id implements Serializable {
        private static final long serialVersionUID = -8270591004786497335L;

        @Column(name="STRATEGYID")
        private int strategyId;

        @Column(name="ALERTID")
        private int alertId;

        public Id() {}

        public Id(int strategyId, int alertId) {
            this.strategyId = strategyId;
            this.alertId = alertId;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + alertId;
            result = prime * result + strategyId;
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if(this == obj)
                return true;
            if(obj == null)
                return false;
            if(getClass() != obj.getClass())
                return false;
            Id other = (Id)obj;
            if(alertId != other.alertId)
                return false;
            if(strategyId != other.strategyId)
                return false;
            return true;
        }

    }    

    @EmbeddedId
    private Id id = new Id();

    @ManyToOne
    @JoinColumn(name="STRATEGYID", insertable=false, updatable=false)
    private Strategy strategy;

    @ManyToOne
    @JoinColumn(name="ALERTID", insertable=false, updatable=false)
    private Alert alert;

    @Column(name="NOMINAL")
    private String nominal;    

    public StrategyAlert() {}

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;    
        // SET ID
        this.id.strategyId = strategy.getId();
    }

    public void setAlert(Alert alert) {
        this.alert = alert;    
        // SET ID
        this.id.alertId = alert.getId();
    }

    // Other Getters & Setters...
}