简体   繁体   English

具有一对多关系映射的“ java.sql.SQLException:字段'id_parent'没有默认值”

[英]“java.sql.SQLException: Field 'id_parent' doesn't have a default value” with one-to-many relationship mapping

Yes, question with such title appeared several times on SO. 是的,这样的标题问题在SO上出现了几次。 However, none of these solutions worked so far. 但是,到目前为止,这些解决方案都没有起作用。 I tried to recreate table and change /etc/my.cnf file. 我试图重新创建表并更改/etc/my.cnf文件。

/etc/my.cnf: /etc/my.cnf中:

datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
symbolic-links=0
sql_mode=NO_ENGINE_SUBSTITUTION

The following program should create the parent object, store it in database, retrieve it, attach child to it and store parent with it's child implicitly with session.save(parent). 下面的程序应创建父对象,将其存储在数据库中,检索它,将子对象附加到该对象,并使用session.save(parent)隐式地将父对象与其子对象存储在一起。 The crashpoint is shown as comment in the source code(Main.java). 崩溃点在源代码(Main.java)中显示为注释。

Database constructor script: 数据库构造函数脚本:

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: 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: 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 Child.java

public class Child {
    private int id;
    private String attribute3;
    // Getters and setters not pasted...
}

child.hbm.xml 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 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 log file: 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

Output: 输出:

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

In table children you define "id_parent" as not null, without a default value. 在表子级中,您将“ id_parent”定义为不为null且没有默认值。

`id_parent` INT UNSIGNED NOT NULL,

As you can note from the hibernate log from the end, there is an attempt to insert into the child table with but one column. 从最后的休眠日志中可以注意到,试图插入只有一列的子表。

Hibernate: 
    into children (attribute3)  values (?)

id_parent will be null in this case, which is not allowed. 在这种情况下,id_parent将为null,这是不允许的。 Possible solutions is either to drop the NOT NULL restriction, or to properly assign the parent id in insertChildren: 可能的解决方案是删除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();
    }
}

Then again, since this is a bi-directional relationship, it would be nice to map it as such: 再说一次,由于这是双向关系,因此将其映射为这样很好:

<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>

You then define a field Parent with appropriate setters/getters (and possibly a constructor taking in parent since it is ALWAYS required) in Child: 然后,您在Child中定义一个带有适当的setters / getters的字段Parent(并且可能由于总是需要构造函数而需要使用parent):

public class Child {
    private int id;
    private String attribute3;
    private Parent parent;
    // Getters and setters not pasted...

    public Child(Parent parent) {
        this.setParent(parent);
    }
}

And finally back to the main: 最后回到主要:

Child child = new Child(parent);

You can now remove the 您现在可以删除

c.setIdParent(parent.getId());

in insertChild() that I mentioned above and all should be peaches. 在上面我提到的insertChild()中,所有都应该是桃子。

More on Hibernate 3 collections 有关Hibernate 3集合的更多信息

As a sidenote I'd recommend using annotations since it's easier to get an overview of the bean mappings having fields and mappings in the same place :) 作为旁注,我建议使用批注,因为这样可以更容易地获得在同一位置具有字段和映射的Bean映射的概述:)

Parent is the owning side of the association (it's the only side, so it has to be the owning one). Parent是关联的拥有方(这是唯一的一方,因此它必须是拥有方)。 Since the join column is not part of the entity which is the owner of the association, Hibernate will generate an update statement to associate Parent and Child when it sees that they are associated in the Parent 's children collection. 由于join列不是属于关联所有者的实体的一部分,因此Hibernate会在看到ParentChild关联到Parentchildren集合中时生成一个update语句来关联ParentChild

That's why the insertion of the Child happens without the value for the join column (and the database complains because it is not nullable). 这就是为什么在没有联接列的值的情况下进行Child插入的原因(数据库抱怨,因为它不可为空)。

You should make the association bidirectional and declare the many side to be the owner of the association (by making the one side inverse ). 你应该让联想双向的,申报的many方面是关联的所有者(通过使oneinverse )。 This way you avoid attempting to store null for the join column and you get rid of the additional update statement. 这样,您可以避免尝试为连接列存储null并摆脱附加的update语句。

Or, to keep your current mappings as they are, just make the join column nullable (but you loose the constraint and execute an unnecessary update statement). 或者,要保持您当前的映射不变,只需使join列可为空(但您可以松开约束并执行不必要的update语句)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 java.sql.SQLException:字段“participant_one_fk_id”没有默认值 - java.sql.SQLException: Field 'participant_one_fk_id' doesn't have a default value java.sql.SQLException:字段没有默认值 - java.sql.SQLException: Field doesn't have a default value Java 实体 java.sql.SQLException:字段“id”没有默认值 - Java Entity java.sql.SQLException: Field 'id' doesn't have a default value java.sql.SQLException: 字段 &#39;supplier_id&#39; 没有默认值 - java.sql.SQLException: Field 'supplier_id' doesn't have a default value Spring Boot java.sql.SQLException:字段“id”没有默认值 - Spring Boot java.sql.SQLException: Field 'id' doesn't have a default value java.sql.SQLException:字段“id”没有默认值 - java.sql.SQLException: Field 'id' doesn't have a default value java.sql.SQLException:字段“register_id”没有默认值 - java.sql.SQLException: Field 'register_id' doesn't have a default value java.sql.SQLException:字段“ client_id”没有默认值 - java.sql.SQLException: Field 'client_id' doesn't have a default value java.sql.SQLException:“字段‘voc_id’没有默认值”。 使用 Spring JPA - java.sql.SQLException: 'Field 'voc_id' doesn't have a default value'. using Spring JPA java.sql.SQLException:field id 没有默认值 - java.sql.SQLException:field id does not have a default value
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM