【问题标题】:Derived Composite Key using JPA 1.0 Annotations (composite key-many-to-one)使用 JPA 1.0 注释的派生复合密钥(复合密钥多对一)
【发布时间】:2015-11-04 13:25:28
【问题描述】:

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

我可以使用以下 Hibernate Mapping 来保持它:

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

我很难弄清楚如何使用 JPA 1.0 中的注释来做到这一点。

这是我目前得到的:

警报类:

@Entity
@Table(name="ALERT")
public class Alert implements Serializable {

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

    @Column(name="NAME")
    private String name;    
}

策略类:

@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 FOREIGN KEY(STRATEGYID) REFERENCES PUBLIC.STRATEGY(STRATEGYID) (0)

我正在使用&lt;property name="hibernate.hbm2ddl.auto" value="create" /&gt; 来生成表格。

如何正确注释 StrategyAlert 类?

【问题讨论】:

    标签: java hibernate jpa annotations


    【解决方案1】:

    看看这个问题:How to implement a complex many to many relationship in JPA?

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

    @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="ALERT")
    public class Alert implements Serializable {
    
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        @Column(name="ALERTID")
        private int id;
    
        @Column(name="NAME")
        private String name;
    
        /**
         * @return the id
         */
        public int getId() {
            return id;
        }
    
        /**
         * @param id the id to set
         */
        public void setId(int id) {
            this.id = id;
        }
    
        /**
         * @return the name
         */
        public String getName() {
            return name;
        }
    
        /**
         * @param name the name to set
         */
        public void setName(String name) {
            this.name = name;
        }
    }
    

    策略

    /**
     * 
     */
    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;
        }
    }
    

    使用该代码,您的测试运行良好(我使用 JPA 1.0.1、Hibernate 3.3.1.GA 和 spring 2.5.5 对其进行了测试)。我使用 H2 作为内存数据库,所以我必须在生成的值中将 Identity 更改为 AUTO,也许你不需要这样做。

    希望有所帮助!

    【讨论】:

    • 感谢弗朗西斯科的帮助 我试过了,我收到一个错误,即 Id 类找不到它的属性:“无法在带有 @IdClass:hib 注释的实体中找到属性(alertId,strategyId)。战略警报”
    • 我已经尝试了所有我能想到的方法,但我无法让它发挥作用。考虑到它在 XML 中是多么容易,您会认为使用 Annotations 应该很容易。有谁知道如何让它工作?
    • 嗨,我更新了我的答案,现在我可以测试代码并为我工作。希望有帮助
    • 我也在使用 H2。我复制/粘贴了您的代码,只是将包重命名为 hib。我收到以下错误:Caused by: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of hib.StrategyAlertPK.alertCaused by: java.lang.IllegalArgumentException: Can not set int field hib.StrategyAlertPK.alert to hib.Alert。我正在使用 HIbernate v3.2.4 我可能会尝试另一个版本,因为我不明白为什么会发生这种情况。
    • 我尝试了最新版本的 Hibernate 我可以使用 - v3.3.1.GA / Annotations 3.4.0.GA / EntityManager 3.4.0.GA 并且我得到完全相同的错误:Can not set int field hib.StrategyAlertPK.alert to hib.Alert。我不知道下一步该尝试什么
    【解决方案2】:

    我找到了解决方案,但我认为这不是正确的方法。

    我有一个用于 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...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-13
      • 2015-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多