是的,有关此类标题的问题多次出现在SO上。但是,迄今为止,这些解决方案都没有奏效。我试图重新创建表并更改/etc/my.cnf文件。
的/etc/my.cnf:
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
sql_mode=NO_ENGINE_SUBSTITUTION
以下程序应该创建父对象,将其存储在数据库中,检索它,将子句附加到它上,并使用session.save(parent)隐式地将父项与其父项一起存储。崩溃点在源代码(Main.java)中显示为注释。
数据库构造函数脚本:
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
CREATE SCHEMA IF NOT EXISTS `dvsscce` ;
USE `dvsscce` ;
CREATE TABLE IF NOT EXISTS `dvsscce`.`parents` (
`id_parent` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`attribute1` VARCHAR(45) NULL,
`attribute2` VARCHAR(45) NULL,
PRIMARY KEY (`id_parent`))
ENGINE = InnoDB
AUTO_INCREMENT = 1;
CREATE TABLE IF NOT EXISTS `dvsscce`.`children` (
`id_child` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`id_parent` INT UNSIGNED NOT NULL,
`attribute3` VARCHAR(45) NULL,
PRIMARY KEY (`id_child`, `id_parent`),
INDEX `fk_children_parent_idx` (`id_parent` ASC),
CONSTRAINT `fk_children_parent`
FOREIGN KEY (`id_parent`)
REFERENCES `dvsscce`.`parents` (`id_parent`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB
AUTO_INCREMENT = 1;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Main.java:
public class Main {
public static void insertParent(Parent p)
{
Session session = SessionContainer.factory.openSession();
Transaction tx = null;
try
{
tx = session.beginTransaction();
session.saveOrUpdate(p);
tx.commit();
}
catch(HibernateException he)
{
if (tx != null) tx.rollback();
he.printStackTrace();
}
finally
{
session.close();
}
}
public static void insertChild(Parent p, Child c)
{
Session session = SessionContainer.factory.openSession();
Transaction tx = null;
try
{
tx = session.beginTransaction();
Query query = session.createQuery("FROM com.mycompany.dvnfsscce.Parent p WHERE p.id = :id_parent");
query.setParameter("id_parent", p.getId());
List results = query.list();
Parent parent = (Parent)results.get(0);
List<Child> finalList = parent.getChildren();
finalList.add(c);
parent.setChildren(finalList);
session.update(parent);
tx.commit(); //crashpoint
}
catch(HibernateException he)
{
if (tx != null) tx.rollback();
he.printStackTrace();
}
finally
{
session.close();
}
}
public static void main(String[] args)
{
Parent parent = new Parent();
parent.setAttribute1("foo");
parent.setAttribute2("bar");
insertParent(parent);
Child child = new Child();
child.setAttribute3(("Quick brown fox"));
insertChild(parent,child);
}
}
Parent.java:
public class Parent {
private int id;
private String attribute1;
private String attribute2;
private List<Child> children = new ArrayList<>();
// Getters and setters not pasted...
}
Child.java
public class Child {
private int id;
private String attribute3;
// Getters and setters not pasted...
}
child.hbm.xml
<hibernate-mapping package="com.mycompany.dvnfsscce">
<class name="Child" table="children">
<id name="id" type="int">
<column name="id_child"/>
<generator class="native"/>
</id>
<property name="attribute3" column="attribute3" type="string"/>
</class>
</hibernate-mapping>
parent.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.mycompany.dvnfsscce">
<class name="Parent" table="parents">
<id name="id" type="int">
<column name="id_parent" not-null="true"/>
<generator class="native"/>
</id>
<property name="attribute1" column="attribute1" type="string"/>
<property name="attribute2" column="attribute2" type="string"/>
<bag name="children" cascade="all" table="children">
<key>
<column name="id_parent" not-null="true" />
</key>
<one-to-many class="Child"/>
</bag>
</class>
</hibernate-mapping>
log4j日志文件:
21:59:24,791 TRACE TypeFactory:72 - Scoping types to session factory org.hibernate.internal.SessionFactoryImpl@4b41dd5c
21:59:36,934 TRACE BasicBinder:81 - binding parameter [1] as [VARCHAR] - [foo]
21:59:36,934 TRACE BasicBinder:81 - binding parameter [2] as [VARCHAR] - [bar]
22:00:22,540 TRACE BasicBinder:81 - binding parameter [1] as [INTEGER] - [1]
22:00:22,634 TRACE BasicExtractor:78 - extracted value ([id_paren1_1_] : [INTEGER]) - [1]
22:00:22,649 TRACE BasicExtractor:78 - extracted value ([attribut2_1_] : [VARCHAR]) - [foo]
22:00:22,649 TRACE BasicExtractor:78 - extracted value ([attribut3_1_] : [VARCHAR]) - [bar]
22:00:22,665 TRACE CollectionType:783 - Created collection wrapper: [com.mycompany.dvnfsscce.Parent.children#1]
22:00:27,462 TRACE BasicBinder:81 - binding parameter [1] as [INTEGER] - [1]
22:06:42,595 TRACE BasicBinder:81 - binding parameter [1] as [VARCHAR] - [Quick brown fox]
22:06:42,781 WARN SqlExceptionHelper:144 - SQL Error: 1364, SQLState: HY000
22:06:42,782 ERROR SqlExceptionHelper:146 - Field 'id_parent' doesn't have a default value
输出:
Hibernate:
/* insert com.mycompany.dvnfsscce.Parent
*/ insert
into
parents
(attribute1, attribute2)
values
(?, ?)
Hibernate:
/*
FROM
com.mycompany.dvnfsscce.Parent p
WHERE
p.id = :id_parent */ select
parent0_.id_parent as id_paren1_1_,
parent0_.attribute1 as attribut2_1_,
parent0_.attribute2 as attribut3_1_
from
parents parent0_
where
parent0_.id_parent=?
Hibernate:
select
children0_.id_parent as id_paren3_1_0_,
children0_.id_child as id_child1_0_0_,
children0_.id_child as id_child1_0_1_,
children0_.attribute3 as attribut2_0_1_
from
children children0_
where
children0_.id_parent=?
Hibernate:
/* insert com.mycompany.dvnfsscce.Child
*/ insert
into
children
(attribute3)
values
(?)
答案 0 :(得分:3)
在表子项中,您将“id_parent”定义为非null,没有默认值。
`id_parent` INT UNSIGNED NOT NULL,
正如您可以从最后的hibernate日志中注意到的那样,尝试使用一列插入子表。
Hibernate:
into children (attribute3) values (?)
在这种情况下,id_parent将为null,这是不允许的。 可能的解决方案是删除NOT NULL限制,或者在insertChildren中正确分配父ID:
public static void insertChild(Parent p, Child c) {
Session session = SessionContainer.factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Query query = session.createQuery("FROM com.mycompany.dvnfsscce.Parent p WHERE p.id = :id_parent");
query.setParameter("id_parent", p.getId());
List results = query.list();
Parent parent = (Parent)results.get(0);
// Here we set the id.
c.setIdParent(parent.getId());
List<Child> finalList = parent.getChildren();
finalList.add(c);
parent.setChildren(finalList);
session.update(parent);
tx.commit(); //crashpoint
} catch(HibernateException he) {
if (tx != null) tx.rollback();
he.printStackTrace();
} finally {
session.close();
}
}
然后再次,因为这是一个双向关系,所以将它映射为这样会很好:
<class name="Parent" table="parents">
<id name="id" type="int">
<column name="id_parent" not-null="true"/>
<generator class="native"/>
</id>
<property name="attribute1" column="attribute1" type="string"/>
<property name="attribute2" column="attribute2" type="string"/>
<set name="children" inverse="true" cascade="all">
<key column="id_parent" not-null="true" />
<one-to-many class="Child"/>
</set>
</class>
<class name="Child" table="children">
<id name="id" type="int">
<column name="id_child"/>
<generator class="native"/>
</id>
<property name="attribute3" column="attribute3" type="string"/>
<many-to-one name="parent" class="Parent" column="id_parent" not-null="true"/>
</class>
然后在Child中定义一个字段Parent,其中包含适当的setter / getters(可能还有一个构造函数,因为它总是需要父项):
public class Child {
private int id;
private String attribute3;
private Parent parent;
// Getters and setters not pasted...
public Child(Parent parent) {
this.setParent(parent);
}
}
最后回到主要:
Child child = new Child(parent);
您现在可以删除
c.setIdParent(parent.getId());
我在上面提到的insertChild()中的都应该是桃子。
More on Hibernate 3 collections
作为旁注,我建议使用注释,因为它更容易概述在同一个地方有字段和映射的bean映射:)
答案 1 :(得分:1)
Parent
是该关联的拥有方(它只是 方面,所以它必须是拥有方)。由于连接列不是作为关联所有者的实体的一部分,因此当Hibernate看到它们在{{1}中关联时,它将生成一个更新语句以关联Parent
和Child
。 {&#39; s Parent
集合。
这就是为什么插入children
而没有连接列的值(并且数据库因为它不可为空而抱怨)的原因。
您应该使关联成为双向关联,并声明Child
方是关联的所有者(通过制作many
方one
)。这样您就可以避免尝试为连接列存储inverse
,并且可以删除其他更新语句。
或者,为了保持当前的映射不变,只需使连接列可以为空(但是你松开约束并执行不必要的更新语句)。