hibernate annotation 一对多保存对象时不能插入外键

时间:2021-02-21 11:55:29
各位大侠,请帮帮小弟吧:在做一对多保存对象时出现不能插入外键的现象,这怎么解决,
@Entity
@Table(name="TEACHERS")
@SequenceGenerator(name="SEQ_TEACHERS",sequenceName="SEQ_TEACHERS")
public class Teacher {


private Long id;

private String code;

private String name;

private String type;

private List<Student> students;

@Id
@GeneratedValue(generator="SEQ_TEACHERS",strategy=GenerationType.SEQUENCE)
@Column(name="id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

@Column(name="CODE")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}

@Column(name="NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

@Column(name="TYPE")
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="TECH_ID",nullable=true,updatable=true)
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
}


@Entity
@Table(name="STUDENTS")
@SequenceGenerator(name="SEQ_STUDENTS",sequenceName="SEQ_STUDENTS")
public class Student {


private Long id;

private String code;

private String name;
// @Column(name="TECH_ID")
// private Long techId;

private Teacher teacher;

@Id
@GeneratedValue(generator="SEQ_STUDENTS",strategy=GenerationType.SEQUENCE)
@Column(name="id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

@Column(name="CODE")
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}

@Column(name="NAME")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

// public Long getTechId() {
// return techId;
// }
// public void setTechId(Long techId) {
// this.techId = techId;
// }

@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="TECH_ID")
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}


public class AssociationsTest {

/**
 * @param args
 */
public static void main(String[] args) {
// SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
    Session session = sessionFactory.openSession();
    Transaction trans = session.beginTransaction();
    Teacher t = new Teacher();
    t.setCode("000001");
    t.setName("xiaoxue");
    t.setType("shuxue");
    List<Student> list = new ArrayList<Student>();
    Student s0 = new Student();
    s0.setCode("000001");
    s0.setName("xioali");
    list.add(s0);
    Student s1 = new Student();
    s1.setCode("000002");
    s1.setName("zhangsan");
    list.add(s1);
    t.setStudents(list);
    session.save(t);
    trans.commit();

}

}

执行到 session.save(t);时,报如下错误:
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:237)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at com.myHibernate.test.AssociationsTest.main(AssociationsTest.java:39)
Caused by: java.sql.BatchUpdateException: ORA-01400: 无法将 NULL 插入 ("SYSTEM"."STUDENTS"."TECH_ID")

at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:367)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:8739)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 8 more

7 个解决方案

#1


你设了级联,你在保存一这方,多的那方也会保存,
但是多的那方你要保证每个字段都有值,或可以为空,或者有默认值。
比如
a  表 e,f,d  三个字段,
b, 表有 x,y,e,e是引用a的e做外键,
你插人a时,
b,也会插,这是b表里只有e这个字段有值,x,y是空的,如果没有默认值,后值不允许为空,
这时 b表就会报错

#2


 刚没看你的代码,就说了堆废话,
映射这里有问题

  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="TECH_ID",nullable=true,updatable=true)

这个注解,改为
   @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER ,mappedBy ="teacher")

#3


@JoinColumn(name="TECH_ID",nullable=true,updatable=true) ,不要

#4


先谢谢,热心的ZuxiangHuang,你的回复给我了点提示。后来经过多次测试,有了问题的解决方案。在注解上的写法上有问题:
Teacher类中的students属性的注解:@OneToMany(fetch=FetchType.EAGER,mappedBy="teacher",cascade=CascadeType.ALL),Student类中的teacher属性上的注解:@ManyToOne @JoinColumn(name="TECH_ID")
在单元测试代码中也有错误,两个student对象要设置teacher属性值,即:s0.setTeacher(t),s1.setTeacher(t),这样的话就可以解决问题了。

#5


还可以看我的博客hibernate 一对多

#6


这是Goods表,商品表


package com.eifashion.brand.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import com.eifashion.portal.model.FuncClassify;

@Entity(name = "brand_goods")
public class Goods implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = 1L;

private String id;
private String name;
private Brand brand;
//商品品牌分类操作
private FuncClassify funClassify;
private List<BrandTagValue> tagValue;
private List<GoodsBarcode> barcodes;

public Goods(String id) {
super();
this.id = id;
}
public Goods(){}
public Goods(String id, String name, Brand brand, FuncClassify funcClassify) {
super();
this.id = id;
this.name = name;
this.brand = brand;
this.funClassify = funcClassify;
}

@Id
public String getId() {
return id;
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "fun_id")
public FuncClassify getFunClassify() {
return funClassify;
}

public void setFunClassify(FuncClassify funClassify) {
this.funClassify = funClassify;
}

@ManyToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinTable(name = "brand_goods_tag", joinColumns = @JoinColumn(name = "goods_id"), inverseJoinColumns = @JoinColumn(name = "tag_id"))
public List<BrandTagValue> getTagValue() {
return tagValue;
}


public void setTagValue(List<BrandTagValue> tagValue) {
this.tagValue = tagValue;
}

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy =
     "good", targetEntity = GoodsBarcode.class)
public List<GoodsBarcode> getBarcodes() {
return barcodes;
}

public void setBarcodes(List<GoodsBarcode> barcodes) {
this.barcodes = barcodes;
}

@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "brand_id")
public Brand getBrand() {
return brand;
}

public void setBrand(Brand brand) {
this.brand = brand;
}

public void addBrandTag(BrandTagValue brandTag){
if(tagValue==null)
tagValue = new ArrayList<BrandTagValue>();
tagValue.add(brandTag);
}

public void addGoodsBar(GoodsBarcode goodsBarcode){
if(goodsBarcode == null)
barcodes = new ArrayList<GoodsBarcode>();
barcodes.add(goodsBarcode);
}
}



这是一个实体的代码,接下来我在发一个实体的代码。
我想

package com.eifashion.portal.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import com.eifashion.brand.model.BrandFuncClassify;
import com.eifashion.brand.model.Goods;
import com.eifashion.common.util.PinYinUtils;

/**
 * 商品功能分类
 * 
 * @author tommyzhao
 * 
 */
@Entity(name = "portal_func_class")
public class FuncClassify implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = 1L;

public final static String DEFAULT_FUNC = "nanzhuang";

private String id;
private FuncClassify parent;
private String name;
private long sort;
private List<FuncClassify> children;
private Date createTime;
private String description;
private List<Goods> goods;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy =
     "funClassify", targetEntity = Goods.class) 
public List<Goods> getGoods() {
return goods;
}

public void addGoods(Goods goods)
{
if(this.goods == null)
{
this.goods = new ArrayList<Goods>();
}
this.goods.add(goods);
}
public void setGoods(List<Goods> goods) {
this.goods = goods;
}

public FuncClassify() {
}

public FuncClassify(String name) {
super();
this.name = name;
this.id = PinYinUtils.toHanyuPinyinString(name);
}

public FuncClassify(String name, String description, FuncClassify parent) {
super();
this.parent = parent;
this.name = name;
this.id = PinYinUtils.toHanyuPinyinString(name);
this.description = description;
this.createTime = new Date();
}

public FuncClassify(String name, String description) {
super();
this.name = name;
this.id = PinYinUtils.toHanyuPinyinString(name);
this.description = description;
this.createTime = new Date();
}

@Id
public String getId() {
return id;
}

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

@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
public FuncClassify getParent() {
return parent;
}

public void setParent(FuncClassify parent) {
this.parent = parent;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public long getSort() {
return sort;
}

public void setSort(long sort) {
this.sort = sort;
}

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent", targetEntity = FuncClassify.class)
public List<FuncClassify> getChildren() {
return children;
}

public void setChildren(List<FuncClassify> children) {
this.children = children;
}

public Date getCreateTime() {
return createTime;
}

public void setCreateTime(Date createTime) {
this.createTime = createTime;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public void addChild(FuncClassify child) {
if (children == null) {
children = new ArrayList<FuncClassify>();
}
children.add(child);
}
}



我想在主键表中先插入数据,外键表后续插入,请问大家有没有什么好的解决方案.以下是我的测试单元,为何外键表插入不了数据。

@Test
 public void addGoods()
 {
Brand brand = new Brand();
FuncClassify funcclass = new FuncClassify();
Goods goods = new  Goods();
goods.setId("aaarr");
goods.setName("bbbb");
brand.addGoods(goods);
funcclass.addGoods(goods);
goodsDAO.addGoods(goods);
 }



#7


引用 6 楼  的回复:
这是Goods表,商品表
Java code


package com.eifashion.brand.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persi……

在goodsDAO.addGoods这段代码前加goods.setFunClassify(FuncClassify funClassify),试试看。

#1


你设了级联,你在保存一这方,多的那方也会保存,
但是多的那方你要保证每个字段都有值,或可以为空,或者有默认值。
比如
a  表 e,f,d  三个字段,
b, 表有 x,y,e,e是引用a的e做外键,
你插人a时,
b,也会插,这是b表里只有e这个字段有值,x,y是空的,如果没有默认值,后值不允许为空,
这时 b表就会报错

#2


 刚没看你的代码,就说了堆废话,
映射这里有问题

  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="TECH_ID",nullable=true,updatable=true)

这个注解,改为
   @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER ,mappedBy ="teacher")

#3


@JoinColumn(name="TECH_ID",nullable=true,updatable=true) ,不要

#4


先谢谢,热心的ZuxiangHuang,你的回复给我了点提示。后来经过多次测试,有了问题的解决方案。在注解上的写法上有问题:
Teacher类中的students属性的注解:@OneToMany(fetch=FetchType.EAGER,mappedBy="teacher",cascade=CascadeType.ALL),Student类中的teacher属性上的注解:@ManyToOne @JoinColumn(name="TECH_ID")
在单元测试代码中也有错误,两个student对象要设置teacher属性值,即:s0.setTeacher(t),s1.setTeacher(t),这样的话就可以解决问题了。

#5


还可以看我的博客hibernate 一对多

#6


这是Goods表,商品表


package com.eifashion.brand.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import com.eifashion.portal.model.FuncClassify;

@Entity(name = "brand_goods")
public class Goods implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = 1L;

private String id;
private String name;
private Brand brand;
//商品品牌分类操作
private FuncClassify funClassify;
private List<BrandTagValue> tagValue;
private List<GoodsBarcode> barcodes;

public Goods(String id) {
super();
this.id = id;
}
public Goods(){}
public Goods(String id, String name, Brand brand, FuncClassify funcClassify) {
super();
this.id = id;
this.name = name;
this.brand = brand;
this.funClassify = funcClassify;
}

@Id
public String getId() {
return id;
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "fun_id")
public FuncClassify getFunClassify() {
return funClassify;
}

public void setFunClassify(FuncClassify funClassify) {
this.funClassify = funClassify;
}

@ManyToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinTable(name = "brand_goods_tag", joinColumns = @JoinColumn(name = "goods_id"), inverseJoinColumns = @JoinColumn(name = "tag_id"))
public List<BrandTagValue> getTagValue() {
return tagValue;
}


public void setTagValue(List<BrandTagValue> tagValue) {
this.tagValue = tagValue;
}

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy =
     "good", targetEntity = GoodsBarcode.class)
public List<GoodsBarcode> getBarcodes() {
return barcodes;
}

public void setBarcodes(List<GoodsBarcode> barcodes) {
this.barcodes = barcodes;
}

@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "brand_id")
public Brand getBrand() {
return brand;
}

public void setBrand(Brand brand) {
this.brand = brand;
}

public void addBrandTag(BrandTagValue brandTag){
if(tagValue==null)
tagValue = new ArrayList<BrandTagValue>();
tagValue.add(brandTag);
}

public void addGoodsBar(GoodsBarcode goodsBarcode){
if(goodsBarcode == null)
barcodes = new ArrayList<GoodsBarcode>();
barcodes.add(goodsBarcode);
}
}



这是一个实体的代码,接下来我在发一个实体的代码。
我想

package com.eifashion.portal.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import com.eifashion.brand.model.BrandFuncClassify;
import com.eifashion.brand.model.Goods;
import com.eifashion.common.util.PinYinUtils;

/**
 * 商品功能分类
 * 
 * @author tommyzhao
 * 
 */
@Entity(name = "portal_func_class")
public class FuncClassify implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = 1L;

public final static String DEFAULT_FUNC = "nanzhuang";

private String id;
private FuncClassify parent;
private String name;
private long sort;
private List<FuncClassify> children;
private Date createTime;
private String description;
private List<Goods> goods;

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy =
     "funClassify", targetEntity = Goods.class) 
public List<Goods> getGoods() {
return goods;
}

public void addGoods(Goods goods)
{
if(this.goods == null)
{
this.goods = new ArrayList<Goods>();
}
this.goods.add(goods);
}
public void setGoods(List<Goods> goods) {
this.goods = goods;
}

public FuncClassify() {
}

public FuncClassify(String name) {
super();
this.name = name;
this.id = PinYinUtils.toHanyuPinyinString(name);
}

public FuncClassify(String name, String description, FuncClassify parent) {
super();
this.parent = parent;
this.name = name;
this.id = PinYinUtils.toHanyuPinyinString(name);
this.description = description;
this.createTime = new Date();
}

public FuncClassify(String name, String description) {
super();
this.name = name;
this.id = PinYinUtils.toHanyuPinyinString(name);
this.description = description;
this.createTime = new Date();
}

@Id
public String getId() {
return id;
}

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

@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
public FuncClassify getParent() {
return parent;
}

public void setParent(FuncClassify parent) {
this.parent = parent;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public long getSort() {
return sort;
}

public void setSort(long sort) {
this.sort = sort;
}

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent", targetEntity = FuncClassify.class)
public List<FuncClassify> getChildren() {
return children;
}

public void setChildren(List<FuncClassify> children) {
this.children = children;
}

public Date getCreateTime() {
return createTime;
}

public void setCreateTime(Date createTime) {
this.createTime = createTime;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public void addChild(FuncClassify child) {
if (children == null) {
children = new ArrayList<FuncClassify>();
}
children.add(child);
}
}



我想在主键表中先插入数据,外键表后续插入,请问大家有没有什么好的解决方案.以下是我的测试单元,为何外键表插入不了数据。

@Test
 public void addGoods()
 {
Brand brand = new Brand();
FuncClassify funcclass = new FuncClassify();
Goods goods = new  Goods();
goods.setId("aaarr");
goods.setName("bbbb");
brand.addGoods(goods);
funcclass.addGoods(goods);
goodsDAO.addGoods(goods);
 }



#7


引用 6 楼  的回复:
这是Goods表,商品表
Java code


package com.eifashion.brand.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persi……

在goodsDAO.addGoods这段代码前加goods.setFunClassify(FuncClassify funClassify),试试看。