Hibernate oracle integrity constraint violated
I got a problem mapping oracle by hibernate
I got these classes
Stock.java
package com.mc.stock;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@Entity
@Table(name = "stock", uniqueConstraints = {
@UniqueConstraint(columnNames = "STOCK_NAME"),
@UniqueConstraint(columnNames = "STOCK_CODE")})
public class Stock implements java.io.Serializable {
private Integer stockId;
private String stockCode;
private String stockName;
private Set<StockDailyRecord> stockDailyRecords = new HashSet<StockDailyRecord>(
0);
public Stock() {
}
public Stock(String stockCode, String stockName) {
this.stockCode = stockCode;
this.stockName = stockName;
}
public Stock(String stockCode, String stockName,
Set<StockDailyRecord> stockDailyRecords) {
this.stockCode = stockCode;
this.stockName = stockName;
this.stockDailyRecords = stockDailyRecords;
}
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_stock_id")
@SequenceGenerator(name = "seq_stock_id", sequenceName = "seq_stock_id", initialValue = 1, allocationSize = 1)
@Basic(optional = false)
@Column(name = "STOCK_ID", unique = true, nullable = false)
public Integer getStockId() {
return this.stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
@Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
public String getStockCode() {
return this.stockCode;
}
public void setStockCode(String stockCode) {
this.stockCode = stockCode;
}
@Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
public String getStockName() {
return this.stockName;
}
public void setStockName(String stockName) {
this.stockName = stockName;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
public Set<StockDailyRecord> getStockDailyRecords() {
return this.stockDailyRecords;
}
public void setStockDailyRecords(Set<StockDailyRecord> stockDailyRecords) {
this.stockDailyRecords = stockDailyRecords;
}
}
StockDailyRecord.java
package com.mc.stock;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
@Entity
@Table(name 开发者_JAVA技巧= "stock_daily_record", uniqueConstraints = @UniqueConstraint(columnNames = "DATEX"))
public class StockDailyRecord implements java.io.Serializable {
private Integer recordId;
private Stock stock;
private Integer priceOpen;
private Integer priceClose;
private Integer priceChange;
private Long volume;
private Date date;
public StockDailyRecord() {
}
public StockDailyRecord(Stock stock, Date date) {
this.stock = stock;
this.date = date;
}
public StockDailyRecord(Stock stock, Integer priceOpen, Integer priceClose,
Integer priceChange, Long volume, Date date) {
this.stock = stock;
this.priceOpen = priceOpen;
this.priceClose = priceClose;
this.priceChange = priceChange;
this.volume = volume;
this.date = date;
}
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_daily_record")
@SequenceGenerator(name = "seq_daily_record", sequenceName = "seq_daily_record", initialValue = 1, allocationSize = 1)
@Basic(optional = false)
@Column(name = "RECORD_ID", unique = true, nullable = false)
public Integer getRecordId() {
return this.recordId;
}
public void setRecordId(Integer recordId) {
this.recordId = recordId;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "STOCK_ID", nullable = false)
public Stock getStock() {
return this.stock;
}
public void setStock(Stock stock) {
this.stock = stock;
}
@Column(name = "PRICE_OPEN", precision = 6)
public Integer getPriceOpen() {
return this.priceOpen;
}
public void setPriceOpen(Integer priceOpen) {
this.priceOpen = priceOpen;
}
@Column(name = "PRICE_CLOSE", precision = 6)
public Integer getPriceClose() {
return this.priceClose;
}
public void setPriceClose(Integer priceClose) {
this.priceClose = priceClose;
}
@Column(name = "PRICE_CHANGE", precision = 6)
public Integer getPriceChange() {
return this.priceChange;
}
public void setPriceChange(Integer priceChange) {
this.priceChange = priceChange;
}
@Column(name = "VOLUME")
public Long getVolume() {
return this.volume;
}
public void setVolume(Long volume) {
this.volume = volume;
}
@Temporal(TemporalType.DATE)
@Column(name = "DATEX", unique = true, nullable = false, length = 10)
public Date getDate() {
return this.date;
}
public void setDate(Date date) {
this.date = date;
}
}
and when I try to run this test:
package com.mc;
import java.util.Date;
import org.hibernate.Session;
import com.mc.stock.Stock;
import com.mc.stock.StockDailyRecord;
import com.mc.util.HibernateUtil;
public class App {
public static void main(String[] args) {
System.out.println("Hibernate one to many (Annotation)");
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Stock stock = new Stock();
stock.setStockCode("7052");
stock.setStockName("PADINI");
session.save(stock);
StockDailyRecord stockDailyRecords = new StockDailyRecord();
stockDailyRecords.setPriceOpen(new Integer("2"));
stockDailyRecords.setPriceClose(new Integer("11"));
stockDailyRecords.setPriceChange(new Integer("10"));
stockDailyRecords.setVolume(30L);
stockDailyRecords.setDate(new Date());
stockDailyRecords.setStock(stock);
stock.getStockDailyRecords().add(stockDailyRecords);
session.save(stockDailyRecords);
session.getTransaction().commit();
System.out.println("Done");
}
}
I get this error:
2011-08-12_02:14:43.296 WARN o.h.util.JDBCExceptionReporter
- SQL Error: 2291, SQLState: 23000
2011-08-12_02:14:43.296 ERROR o.h.util.JDBCExceptionReporter
- ORA-02291: integrity constraint (HX.SYS_C004028) violated - parent key not found
2011-08-12_02:14:43.296 WARN o.h.util.JDBCExceptionReporter
- SQL Error: 2291, SQLState: 23000
2011-08-12_02:14:43.296 ERROR o.h.util.JDBCExceptionReporter
- ORA-02291: integrity constraint (HX.SYS_C004028) violated - parent key not found
Exception in thread "main" org.hibernate.exception.ConstraintViolationException:
Could not execute JDBC batch update
I'm new to hibernate and I would thank any help on this
Thanks in advance.
You are not setting the contents of the Set from stock (setStockDailyRecords). I would try annotating setStockDailyRecords
as
@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock", inverse = "true")
That means that the set is not directly created in the database, they retrieve it using the inverse relationship (through the FK in StockDailyRecord)
UPDATED to answer MHERO's first comment.
Check http://docs.jboss.org/hibernate/core/3.3/reference/en/html/collections.html#collections-mapping for the inverse attribute.
Other option that you have is to move save(stock) just before the session is closed (remember to set the Set of setStockDailyRecords with the appropiate values.
So HX.SYS_C004028
is the name of the foreign key between the STOCK and STOCKDAILYRECORD tables. This is a database constraint which enforces a business rule, every STOCKDAILYRECORD must belong to one and only one STOCK record.
The constraint will link a column on STOCKDAILYRECORD with the primary key of the STOCK table. If you have a sane data model, the columns will share the same name, and I would hope that it is the STOCKCODE column.
You can check whether this is the case by querying the data dictionary:
select column_name from all_cons_columns
where owner = 'HX'
and constraint_name = 'SYS_C004028'
/
(incidentally, having system-generated constraint names sucks: we can include meaningful names when we create constraints, which is really helpful when trying to investigate things like this.)
You are not populating the STOCKCODE. So maybe Hibernate is handling that, and not doing it properly. For instance, the default Hibernate behaviour is to inser child records before the parent. There are a couple of ways around it, but the best way is to configure Hibernate so that it enforces a uni-directional one-to-many mapping on the child foreign key column. This is done by setting the not-null
property:
<set name="stockDailyRecord" lazy="true" cascade="all-delete-orphan">
<key column="STOCK_CODE_FK" not-null=”true” update=”false”/>
<one-to-many class="com.stock.dto.episode.StockDailyRecordDTO"/>
</set>
(your naming conventions will vary)
精彩评论