Reputation: 279
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?
Upvotes: 1
Views: 203
Reputation: 2468
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!
Upvotes: 1
Reputation: 279
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...
}
Upvotes: 0