&引用;java.sql.SQLException:字段';id#u父项';不';“没有默认值”;使用一对多关系映射

&引用;java.sql.SQLException:字段';id#u父项';不';“没有默认值”;使用一对多关系映射,java,mysql,sql,hibernate,Java,Mysql,Sql,Hibernate,是的,这样的题目出现了好几次。然而,到目前为止,这些解决方案都不起作用。我试图重新创建表并更改/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)隐式地存储父对象及其子

是的,这样的题目出现了好几次。然而,到目前为止,这些解决方案都不起作用。我试图重新创建表并更改/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);
    }
}
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>
输出:

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
            (?)

在表子项中,您将“id\u parent”定义为非空,没有默认值

`id_parent` INT UNSIGNED NOT NULL,
正如您从hibernate日志的末尾所注意到的,有人试图插入到只有一列的子表中

Hibernate: 
    into children (attribute3)  values (?)
在这种情况下,id_parent将为null,这是不允许的。 可能的解决方案是删除NOTNULL限制,或在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();
    }
}
最后回到主题:

Child child = new Child(parent);
现在可以删除

c.setIdParent(parent.getId());
在我上面提到的insertChild()中,所有的都应该是桃子


作为旁注,我建议使用注释,因为在同一位置可以更容易地获得具有字段和映射的bean映射的概述:)

在表子级中,您将“id\u parent”定义为非空,没有默认值

`id_parent` INT UNSIGNED NOT NULL,
正如您从hibernate日志的末尾所注意到的,有人试图插入到只有一列的子表中

Hibernate: 
    into children (attribute3)  values (?)
在这种情况下,id_parent将为null,这是不允许的。 可能的解决方案是删除NOTNULL限制,或在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();
    }
}
最后回到主题:

Child child = new Child(parent);
现在可以删除

c.setIdParent(parent.getId());
在我上面提到的insertChild()中,所有的都应该是桃子


作为旁注,我建议使用注释,因为在同一个位置上有字段和映射的bean映射更容易获得概述:)

Parent
是关联的拥有方(它是唯一的一方,因此它必须是拥有方)。由于联接列不是作为关联所有者的实体的一部分,Hibernate将生成一个update语句,当它看到父项和子项在父项的子项集合中关联时,将它们关联起来

这就是为什么插入
时没有join列的值(数据库会抱怨,因为它不可为null)

您应该使关联双向,并声明
many
侧为关联的所有者(通过使
one
反向
)。这样可以避免尝试为join列存储
null
,并摆脱额外的update语句


或者,要保持当前映射的原样,只需将联接列设置为空(但您会放松约束并执行不必要的update语句)。

Parent
是关联的拥有方(它是唯一的一方,因此必须是拥有方)。由于联接列不是作为关联所有者的实体的一部分,Hibernate将生成一个update语句,当它看到父项和子项在父项的子项集合中关联时,将它们关联起来

这就是为什么插入
时没有join列的值(数据库会抱怨,因为它不可为null)

您应该使关联双向,并声明
many
侧为关联的所有者(通过使
one
反向
)。这样可以避免尝试为join列存储
null
,并摆脱额外的update语句


或者,为了保持当前映射的原样,只需将联接列设为null即可(但您放松了约束并执行了一个不必要的update语句)。

出于好奇,您是否能够正常工作?@péturValdimarsson否,我遇到了另一个错误。“not null属性引用null或瞬态值”我决定实现向后导航功能,即在子类中创建,并在这个类中添加了带有getter和setter的“parent”字段。出于好奇,您是否可以使用它?@PéturValdimarsson否,我遇到了另一个错误。“not null属性引用null或瞬态值”我决定实现向后导航,即在子级中创建并添加“父级”此类中包含getters和setters.org.hibernate.PropertyValueException的字段:not null属性使用第二种解决方案引用null或瞬态值:com.mycompany.dvnfsscce.Child.parent。啊,忘记在main中设置父级,您的答案是正确的。Sweet:)希望您能继续使用它。冬眠可以很有趣。请记住,这里有一个轻微的范式转换,因为您可以将实体视为数据库的扩展。一旦你改变了一个对象,就认为它在数据库中改变了(好吧,这不是完全正确的,但首先是一个好的心理图像)。需要一段时间才能习惯.org.hibernate.PropertyValueException:not null属性引用空值或暂时值:com.mycompany.dvnfsscce.Child.parent使用第二个解决方案。啊,忘记在main中设置父级,您的答案是正确的。Sweet:)希望您能继续使用此解决方案。冬眠可以很有趣。请记住,这里有一个轻微的范式转换,因为您可以将实体视为数据库的扩展。一旦你改变了一个对象,就认为它在数据库中改变了(好吧,这不是完全正确的,但首先是一个好的心理图像)。需要一段时间来适应。
c.setIdParent(parent.getId());