简体   繁体   中英

Derived Composite Key using JPA 1.0 Annotations (composite key-many-to-one)

在此处输入图片说明

I have a simple relationship as shown in the diagram above.

I can persist this using the following 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>

I am having a really hard time trying to figure out how to do this using Annotations in JPA 1.0.

Here's what I've got so far:

Alert Class:

@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;    
}

Strategy 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 class:

public class StrategyAlertPK implements Serializable {

    private int strategyId;
    private int alertId;
}

StrategyAlert class:

@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;
}

Test Case:

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();      

I'm getting the following error:

Referential integrity constraint violation: "FK80432DA9CE00672E: PUBLIC.STRATEGYALERT FOREIGN KEY(STRATEGYID) REFERENCES PUBLIC.STRATEGY(STRATEGYID) (0)

I'm using <property name="hibernate.hbm2ddl.auto" value="create" /> to generate the tables.

How do I annotate the StrategyAlert class correctly?

Take a look at this questions: How to implement a complex many to many relationship in JPA?

I think the problem here is you have to join the Id declaration and the manyToOne declaration as described in JPA 1, I can´t test the code right now, but more or less it has to be like this

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

UPDATE

Hi,

now I can test the code, and is working for m with the following code (some minors corrections):

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

Strategy

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

StrategyAlertPK

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


}

StrategyAlert

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

With that code your test is running OK (I tested it with JPA 1.0.1, Hibernate 3.3.1.GA and spring 2.5.5). I am using H2 as memory database so I had to change Identity to AUTO in generated values, maybe you don´t need to do that.

Hope helps!

I have found a solution but I don't think this is the correct way to do it.

I have a static nested class for the ID. Then in both setter methods I also set the ID. This seems a very manual way to do it and surely there must be a better way?

@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...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM