Hibernate与复合键的一对多关系(SAVE操作)

时间:2018-01-12 03:15:26

标签: java hibernate hibernate-mapping

表脚本:

DROP TABLE IF EXISTS STOCK; CREATE TABLE STOCK (   STOCK_ID INT(10) NOT NULL,   STOCK_CODE VARCHAR(10) NOT NULL,   STOCK_NAME VARCHAR(20) NOT NULL,   PRIMARY KEY (STOCK_ID,STOCK_CODE),   KEY STOCK_CODE_IDX (STOCK_CODE) ); 
DROP TABLE IF EXISTS STOCK_DAILY_RECORD; 

CREATE TABLE  STOCK_DAILY_RECORD (   RECORD_ID INT(10) NOT NULL,   STOCK_CODE VARCHAR(10) NOT NULL,   PRICE_OPEN FLOAT(6,2) DEFAULT NULL,   PRICE_CLOSE FLOAT(6,2) DEFAULT NULL,   PRICE_CHANGE FLOAT(6,2) DEFAULT NULL,   VOLUME BIGINT(20) DEFAULT NULL,   STOCK_ID INT(10) NOT NULL,   PRIMARY KEY (RECORD_ID,STOCK_CODE),   KEY FK_STOCK_ID (STOCK_ID,STOCK_CODE),   CONSTRAINT FK_STOCK_ID FOREIGN KEY (STOCK_ID,STOCK_CODE) REFERENCES STOCK (STOCK_ID,STOCK_CODE) ) ;

这是我可以填充实体类以在stockstockdailyrecord表中保存值的主类:

package org.hibernate.HibernateEntity;

import org.hibernate.Session;

import com.model.Stock;
import com.model.StockDailyRecord;
import com.model.StockDailyRecordId;
import com.model.StockId;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main(String[] args) {
        System.out.println("Hibernate one to one (Annotation)");
        Session session = HibernateUtil.getSessionFactory().openSession();

        session.beginTransaction();

        Stock stock = new Stock();
        StockId id = new StockId(2, "7052");
        stock.setId(id);
        stock.setStockName("PADINI");

        StockDailyRecord stockDetail = new StockDailyRecord();
        StockDailyRecordId id1 = new StockDailyRecordId(101, "7052");
        stockDetail.setId(id1);
        stockDetail.setPriceChange(200.0f);
        stockDetail.setPriceClose(210.0f);
        stockDetail.setPriceOpen(120.0f);
        stockDetail.setVolume(12l);
        stock.getStockDailyRecords().add(stockDetail);
        stockDetail.setStock(stock);

        session.save(stock);
        //session.save(stockDetail);
        session.getTransaction().commit();
        System.out.println("Done");
    }
}

使用嵌入了hibernate和id:

的复合键配置的实体类
package com.model;
// Generated Jan 12, 2018 8:17:38 AM by Hibernate Tools 5.2.6.Final

import java.util.HashSet;
import java.util.Set;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

/**
 * Stock generated by hbm2java
 */
@Entity
@Table(name = "stock", catalog = "testdb")
public class Stock implements java.io.Serializable {

    private StockId id;
    private String stockName;
    private Set<StockDailyRecord> stockDailyRecords = new HashSet<StockDailyRecord>(0);

    public Stock() {
    }

    public Stock(StockId id, String stockName) {
        this.id = id;
        this.stockName = stockName;
    }

    public Stock(StockId id, String stockName, Set<StockDailyRecord> stockDailyRecords) {
        this.id = id;
        this.stockName = stockName;
        this.stockDailyRecords = stockDailyRecords;
    }

    @EmbeddedId

    @AttributeOverrides({ @AttributeOverride(name = "stockId", column = @Column(name = "STOCK_ID", nullable = false)),
            @AttributeOverride(name = "stockCode", column = @Column(name = "STOCK_CODE", nullable = false, length = 10)) })
    public StockId getId() {
        return this.id;
    }

    public void setId(StockId id) {
        this.id = id;
    }

    @Column(name = "STOCK_NAME", nullable = false, length = 20)
    public String getStockName() {
        return this.stockName;
    }

    public void setStockName(String stockName) {
        this.stockName = stockName;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
    @Cascade(CascadeType.ALL)
    public Set<StockDailyRecord> getStockDailyRecords() {
        return this.stockDailyRecords;
    }

    public void setStockDailyRecords(Set<StockDailyRecord> stockDailyRecords) {
        this.stockDailyRecords = stockDailyRecords;
    }

}

使用嵌入了hibernate和id:

的复合键配置的实体类
package com.model;
// Generated Jan 12, 2018 8:17:38 AM by Hibernate Tools 5.2.6.Final

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 * StockDailyRecord generated by hbm2java
 */
@Entity
@Table(name = "stock_daily_record", catalog = "testdb")
public class StockDailyRecord implements java.io.Serializable {

    private StockDailyRecordId id;
    private Stock stock;
    private Float priceOpen;
    private Float priceClose;
    private Float priceChange;
    private Long volume;

    public StockDailyRecord() {
    }

    public StockDailyRecord(StockDailyRecordId id, Stock stock) {
        this.id = id;
        this.stock = stock;
    }

    public StockDailyRecord(StockDailyRecordId id, Stock stock, Float priceOpen, Float priceClose, Float priceChange,
            Long volume) {
        this.id = id;
        this.stock = stock;
        this.priceOpen = priceOpen;
        this.priceClose = priceClose;
        this.priceChange = priceChange;
        this.volume = volume;
    }

    @EmbeddedId

    @AttributeOverrides({ @AttributeOverride(name = "recordId", column = @Column(name = "RECORD_ID", nullable = false)),
            @AttributeOverride(name = "stockCode", column = @Column(name = "STOCK_CODE", nullable = false, length = 10)) })
    public StockDailyRecordId getId() {
        return this.id;
    }

    public void setId(StockDailyRecordId id) {
        this.id = id;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
            @JoinColumn(name = "STOCK_ID", referencedColumnName = "STOCK_ID", nullable = false, insertable = false, updatable = false),
            @JoinColumn(name = "STOCK_CODE", referencedColumnName = "STOCK_CODE", nullable = false, insertable = false, updatable = false) })
    public Stock getStock() {
        return this.stock;
    }

    public void setStock(Stock stock) {
        this.stock = stock;
    }

    @Column(name = "PRICE_OPEN", precision = 6)
    public Float getPriceOpen() {
        return this.priceOpen;
    }

    public void setPriceOpen(Float priceOpen) {
        this.priceOpen = priceOpen;
    }

    @Column(name = "PRICE_CLOSE", precision = 6)
    public Float getPriceClose() {
        return this.priceClose;
    }

    public void setPriceClose(Float priceClose) {
        this.priceClose = priceClose;
    }

    @Column(name = "PRICE_CHANGE", precision = 6)
    public Float getPriceChange() {
        return this.priceChange;
    }

    public void setPriceChange(Float priceChange) {
        this.priceChange = priceChange;
    }

    @Column(name = "VOLUME")
    public Long getVolume() {
        return this.volume;
    }

    public void setVolume(Long volume) {
        this.volume = volume;
    }

}

使用嵌入了hibernate和id:

的复合键配置的实体类
package com.model;
// Generated Jan 12, 2018 8:17:38 AM by Hibernate Tools 5.2.6.Final

import javax.persistence.Column;
import javax.persistence.Embeddable;

/**
 * StockDailyRecordId generated by hbm2java
 */
@Embeddable
public class StockDailyRecordId implements java.io.Serializable {

    private int recordId;
    private String stockCode;

    public StockDailyRecordId() {
    }

    public StockDailyRecordId(int recordId, String stockCode) {
        this.recordId = recordId;
        this.stockCode = stockCode;
    }

    @Column(name = "RECORD_ID", nullable = false)
    public int getRecordId() {
        return this.recordId;
    }

    public void setRecordId(int recordId) {
        this.recordId = recordId;
    }

    @Column(name = "STOCK_CODE", nullable = false, length = 10)
    public String getStockCode() {
        return this.stockCode;
    }

    public void setStockCode(String stockCode) {
        this.stockCode = stockCode;
    }

    public boolean equals(Object other) {
        if ((this == other))
            return true;
        if ((other == null))
            return false;
        if (!(other instanceof StockDailyRecordId))
            return false;
        StockDailyRecordId castOther = (StockDailyRecordId) other;

        return (this.getRecordId() == castOther.getRecordId())
                && ((this.getStockCode() == castOther.getStockCode()) || (this.getStockCode() != null
                        && castOther.getStockCode() != null && this.getStockCode().equals(castOther.getStockCode())));
    }

    public int hashCode() {
        int result = 17;

        result = 37 * result + this.getRecordId();
        result = 37 * result + (getStockCode() == null ? 0 : this.getStockCode().hashCode());
        return result;
    }

}

使用嵌入了hibernate和id:

的复合键配置的实体类
package com.model;
// Generated Jan 12, 2018 8:17:38 AM by Hibernate Tools 5.2.6.Final

import javax.persistence.Column;
import javax.persistence.Embeddable;

/**
 * StockId generated by hbm2java
 */
@Embeddable
public class StockId implements java.io.Serializable {

    private int stockId;
    private String stockCode;

    public StockId() {
    }

    public StockId(int stockId, String stockCode) {
        this.stockId = stockId;
        this.stockCode = stockCode;
    }

    @Column(name = "STOCK_ID", nullable = false)
    public int getStockId() {
        return this.stockId;
    }

    public void setStockId(int stockId) {
        this.stockId = stockId;
    }

    @Column(name = "STOCK_CODE", nullable = false, length = 10)
    public String getStockCode() {
        return this.stockCode;
    }

    public void setStockCode(String stockCode) {
        this.stockCode = stockCode;
    }

    public boolean equals(Object other) {
        if ((this == other))
            return true;
        if ((other == null))
            return false;
        if (!(other instanceof StockId))
            return false;
        StockId castOther = (StockId) other;

        return (this.getStockId() == castOther.getStockId())
                && ((this.getStockCode() == castOther.getStockCode()) || (this.getStockCode() != null
                        && castOther.getStockCode() != null && this.getStockCode().equals(castOther.getStockCode())));
    }

    public int hashCode() {
        int result = 17;

        result = 37 * result + this.getStockId();
        result = 37 * result + (getStockCode() == null ? 0 : this.getStockCode().hashCode());
        return result;
    }

}

用于使用hibernate配置创建会话工厂的类:

package org.hibernate.HibernateEntity;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void shutdown() {
        // Close caches and connection pools
        getSessionFactory().close();
    }

}

Stockdailyrecord 没有填充库存ID,请提供建议。

        08:20:05.202 [main] DEBUG org.hibernate.pretty.Printer - listing entities:
        08:20:05.203 [main] DEBUG org.hibernate.pretty.Printer - com.model.StockDailyRecord{priceChange=200.0, volume=12, priceClose=210.0, priceOpen=120.0, id=component[recordId,stockCode]{recordId=101, stockCode=7052}, stock=com.model.Stock#component[stockCode,stockId]{stockId=2, stockCode=7052}}
        08:20:05.203 [main] DEBUG org.hibernate.pretty.Printer - com.model.Stock{stockName=PADINI, stockDailyRecords=[com.model.StockDailyRecord#component[recordId,stockCode]{recordId=101, stockCode=7052}], id=component[stockCode,stockId]{stockId=2, stockCode=7052}}
        08:20:05.205 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
        08:20:05.206 [main] DEBUG org.hibernate.SQL - insert into testdb.stock (STOCK_NAME, STOCK_CODE, STOCK_ID) values (?, ?, ?)
        08:20:05.207 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1
        08:20:05.271 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
        08:20:05.271 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
        08:20:05.271 [main] DEBUG org.hibernate.SQL - insert into testdb.stock_daily_record (PRICE_CHANGE, PRICE_CLOSE, PRICE_OPEN, VOLUME, RECORD_ID, STOCK_CODE) values (?, ?, ?, ?, ?, ?)
        08:20:05.277 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - Executing batch size: 1
        08:20:05.300 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
        08:20:05.315 [main] DEBUG o.h.util.JDBCExceptionReporter - Could not execute JDBC batch update [insert into testdb.stock_daily_record (PRICE_CHANGE, PRICE_CLOSE, PRICE_OPEN, VOLUME, RECORD_ID, STOCK_CODE) values (?, ?, ?, ?, ?, ?)]
        java.sql.BatchUpdateException: Field 'STOCK_ID' doesn't have a default value
            at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2024) ~[mysql-connector-java-5.1.15.jar:na]
            at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449) ~[mysql-connector-java-5.1.15.jar:na]
            at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) ~[hibernate-core-3.6.3.Final.jar:3.6.3.Final]
            at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268) ~[hibernate-core-3.6.3.Final.jar:3.6.3.Final]
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268) [hibernate-core-3.6.3.Final.jar:3.6.3.Final]
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184) [hibernate-core-3.6.3.Final.jar:3.6.3.Final]
            at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) [hibernate-core-3.6.3.Final.jar:3.6.3.Final]
            at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) [hibernate-core-3.6.3.Final.jar:3.6.3.Final]
            at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) [hibernate-core-3.6.3.Final.jar:3.6.3.Final]
            at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383) [hibernate-core-3.6.3.Final.jar:3.6.3.Final]
            at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133) [hibernate-core-3.6.3.Final.jar:3.6.3.Final]
            at org.hibernate.HibernateEntity.App.main(App.java:40) [classes/:na]
        Caused by: java.sql.SQLException: Field 'STOCK_ID' doesn't have a default value
            at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073) ~[mysql-connector-java-5.1.15.jar:na]
            at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3603) ~[mysql-connector-java-5.1.15.jar:na]
            at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3535) ~[mysql-connector-java-5.1.15.jar:na]
            at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1989) ~[mysql-connector-java-5.1.15.jar:na]
            at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2150) ~[mysql-connector-java-5.1.15.jar:na]
            at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2626) ~[mysql-connector-java-5.1.15.jar:na]
            at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119) ~[mysql-connector-java-5.1.15.jar:na]
            at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2415) ~[mysql-connector-java-5.1.15.jar:na]
            at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1976) ~[mysql-connector-java-5.1.15.jar:na]
            ... 11 common frames omitted
        08:20:05.316 [main] WARN  o.h.util.JDBCExceptionReporter - SQL Error: 1364, SQLState: HY000
        08:20:05.316 [main] ERROR o.h.util.JDBCExceptionReporter - Field 'STOCK_ID' doesn't have a default value
        Exception in thread "main" org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
            at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140)
            at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128)
            at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
            at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
            at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
            at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
            at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
            at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
            at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
            at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
            at org.hibernate.HibernateEntity.App.main(App.java:40)
        Caused by: java.sql.BatchUpdateException: Field 'STOCK_ID' doesn't have a default value
            at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2024)
            at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449)
            at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
            at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
            ... 8 more
        Caused by: java.sql.SQLException: Field 'STOCK_ID' doesn't have a default value
            at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
            at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3603)
            at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3535)
            at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1989)
            at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2150)
            at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2626)
            at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
            at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2415)
            at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1976)
            ... 11 more

2 个答案:

答案 0 :(得分:0)

由于您没有填写字段STOCK_ID但是它在数据库中无法为空,因此引发了错误。添加子句AUTO_INCREMENT以防止表STOCK中的字段STOCK_ID:

STOCK_ID INT(10) NOT NULL AUTO_INCREMENT

和表STOCK_DAILY_RECORD中的RECORD_ID:

RECORD_ID INT(10) NOT NULL AUTO_INCREMENT

但请记住,STOCK_CODE也不是null,你必须在插入之前填充它。

答案 1 :(得分:0)

您可以在创建实体实例的位置发布代码并保存吗?错误是自我解释的。您必须设置STOCK_ID的值。你想让它成为一个标识列(mysql中的auto_increment)吗?如果是这种情况,请更改数据模型以将STOCK_ID声明为标识,并为stockId添加@GeneratedValue(strategy = GenerationType.IDENTITY)。