7

Hibernate 抛出以下异常:

Caused by: java.sql.SQLException: Field 'catVerb_id' doesn't have a default value

人们说问题出在我的没有 AUTO_INCREMENT 语句的 PK 上,但是你可以看到我已经在我的数据库中完成了这个并且问题仍然存在。所以,我带来了我的课程和我的数据库实现。

我认为我的问题出在测试课上......有人可以告诉我如何测试这个吗?

(是的,有些词是葡萄牙语,但你可以理解)。

类别Verbete

@Entity
@Table(name="verbete_categoria")
public class CategoriaVerbete implements Serializable{
    private long id;
    private String nome;
    private String descricao;
    private int serie;
    private Set<Verbete> verbetes = new HashSet<Verbete>();
    private Set<SignificadosVerbete> significados = new HashSet<SignificadosVerbete>();

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="catVerb_id")
    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }

    ...

    @OneToMany(cascade = {CascadeType.ALL})
    @JoinColumn(name="catVerb_id", nullable = true) 
    public Set<Verbete> getVerbetes() {
        return verbetes;
    }
    public void setVerbetes(Set<Verbete> verbetes) {
        this.verbetes = verbetes;
    }

    @OneToMany(cascade = {CascadeType.ALL})
    @JoinColumn(name="catVerb_id", nullable = true)
    public Set<SignificadosVerbete> getSignificados() {
        return significados;
    }
    public void setSignificados(Set<SignificadosVerbete> significados) {
        this.significados = significados;
    }

}

动词

@Entity
@Table(name="verbete")
public class Verbete implements Serializable{
   ...

    @ManyToOne
    @JoinColumn(name="catVerb_id", insertable = false, updatable = false)
    public CategoriaVerbete getCategoria() {
        return categoria;
    }
    public void setCategoria(CategoriaVerbete categoria) {
        this.categoria = categoria;
    }

    ...
}

意义动词

@Entity
@Table(name="verbete_significados")
public class SignificadosVerbete {
    ... 

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name="catVerb_id", insertable = false, updatable = false)
    public CategoriaVerbete getCategoria() {
        return categoria;
    }
    public void setCategoria(CategoriaVerbete categoria) {
        this.categoria = categoria;
    }

   ...

}

在数据库...

CREATE TABLE verbete_categoria (
catVerb_id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
catVerb_nome VARCHAR(100) UNIQUE,
catVerb_descricao MEDIUMTEXT,
catVerb_serie INT NOT NULL
);

任何帮助将不胜感激,谢谢。

更新 - 问题已解决

好吧,我期待一个胜利的配乐,但没关系...

我只是按照这个链接所说的:

https://www.ibm.com/developerworks/community/blogs/fd26864d-cb41-49cf-b719-d89c6b072893/entry/como_criar_relacionamento_onetomany_com_hibernate?lang=en

我读到 Hibernate 文档不推荐该链接中的内容,但我尝试遵循建议并通过一周的时间处理错误。所以,我希望这对其他人有所帮助。

并感谢所有的答案。

4

4 回答 4

6

我相信这SignificadosVerbete是导致问题的插入cannot be null(我强烈建议您打开 sql trace 以查看导致问题的查询)。

这是双向一对多关系的常见问题。你所拥有的是这样的:

class Foo {
    @Id
    @Column("foo_id")
    Long id;

    @OneToMany(cascade=ALL)
    @JoinColumn("foo_id")
    Set<Bar> bars;
}

class Bar {
    @Id
    @Column("bar_id")
    Long id;

    @ManyToOne
    @JoinColumn("foo_id", insertable=false, updatable=false)
    Foo foo;
}

这种映射会导致关系为 所拥有Foo,这将创建多个insert+update语句:当您插入 aFoo时,带有 2 Bars,会发生的是它会先插入 that Foo,然后 2 Bar没有FK foo_id。然后将为每个更新发出两次更新以更新表中Bar的正确值。foo_idBar

通常我们不会以这种方式映射双向OneToMany映射,而是这样做:

class Foo {
    @Id
    @Column("foo_id")
    Long id;

    @OneToMany(mappedBy="foo", cascade=ALL)
    Set<Bar> bars;
}

class Bar {
    @Id
    @Column("bar_id")
    Long id;

    @ManyToOne
    @JoinColumn("foo_id")
    Foo foo;
}

通过这样做,该关系归 拥有Bar,并且当您按照我描述的方式插入时,您将插入 1Foo和 2Bar已经将2foo_id作为插入的一部分。

这就是我们通常在 Hibernate 中进行双向关系的方式。

于 2014-11-28T06:11:46.747 回答
3

我同意提供的链接。它按照链接工作。据我了解,删除以下部分确实对我有用。

前:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="catVerb_id", insertable = false, updatable = false)

后:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="catVerb_id")
于 2014-07-29T05:50:32.287 回答
1

java.sql.SQLException:字段“xxxx”没有默认值

(又名。间接 Fetch.LAZY 加载问题)

我今天遇到了这个问题。

原来是我的情况的几个问题。

我发现必须修复的第一件事是有问题的列表需要延迟加载。LAZY LOADED 我的意思是当数据库“处于会话中”时必须从数据库中访问它。现在我发现在处理 Fetch.LAZY 时必须做一个小技巧,这样当您将引用对象加载到容器中时,您需要(看似不必要地)调用引用对象的方法。仅仅返回引用是不够的,即使在会话对象中也是如此。

例如,不要只是这样说:

public List<Apple> getApples(Kid kid) throws KidNotFoundException 
{
    log.info("getApples (service) called"); 
    kid = get(kid);
    List<Apple> list = kid.getApples();
    return list;
}

您必须再添加一个看似微不足道的步骤。要触发 JPA 的延迟加载机制,您需要在引用对象本身上调用一个方法(并且它仅在 JPA 事务中有效,无论是直接的还是通过 @Stateless 标记隐含的)。直到你这样做,JPA 将尽最大努力不要将不必要的对象加载到内存中(也就是Fetch.LAZY 背后的整个想法)。

所以在这种情况下,我在检索到的(Fetch.LAZY designation)对象“list”上调用一个方法:

 list.size();

可以调用对象上的任何方法来触发 JPA 加载对象(或对象),在这种情况下,我只是调用 list.size() 方法非常方便,它看起来并不像刚才那样格格不入调用一个看似不必要的 child.getName(); 从专业的角度来看。我多么希望一个关于 Fetch.LAZY 的好教程能够向我指出这一切。我猜是另一本书的素材...

这会强制 JPA 从数据库中实际加载引用的对象。

public List<Apple> getApples(Kid kid) throws KidNotFoundException 
{
    log.info("getApples (service) called"); 
    kid = get(kid);
    List<Apple> list = kid.getApples();
    list.size();
    return list;
}

在我的情况下,这是生成“java.sql.SQLException:字段'xxxx'没有默认值”消息的第一个问题。

第二个问题与两个表之间配置不正确的@ManyToMany 关系有关。今天,我花了大约五分钟的时间从我之前创建的原型中建立我认为的多对多关系。拉扯头发大约需要六个小时才能解决扭结。无论如何,这就是我最终为解决我的情况所做的事情。

/**
 * "Buckets"
 * an Apple can be give to 0-to-n Kids ... 
 */

@ManyToMany(cascade=CascadeType.PERSIST)
@JoinTable(name="Buckets",
    joinColumns=@JoinColumn(name="Apple_id"),
    inverseJoinColumns=@JoinColumn(name="Kid_id"))
private List<Kid> kids;

public List<Kid> getKids() {
    return kids;
}

public void setKids(List<Kid> kids) {
    this.kids = kids;
}

. . .

/**
 * a Kid can have 0-n Apples
 */

@ManyToMany(mappedBy="kids", cascade=CascadeType.PERSIST)
private List<Apple> apples;

在我的情况下,我原来的 @ManyToMany 设置引用了错误的表这一事实导致了这个错误。但是 LAZY LOAD 情况的简单修复立即解决了 'java.sql.SQLException: Field 'xxxx' doesn't have a default value' 问题。

佩里

附言。经过一整天的努力,我确实学到了一些隐藏在 JPA 粗糙外表下的巧妙技巧(也就是网上冲浪和阅读有关如何有效使用 @ManyToMany 关系的文档)。这样上述配置将动态创建第三个数据库表,看起来就像您手动创建它一样好。就一对一的关系而言,它还加强了 Kids 和 Apples 之间的独特关系。以及在数据库中只创建一个额外的表,而不是在数据库中需要两个相同的表。实际上,在我的情况下,我在这个 @ManyToMany 构造之前有 2 个表:

儿童苹果

由于上面列出的 @ManyTo@Many 构造,我现在有 3 个:

儿童苹果桶

Buckets 表中只有两个字段,Apple_id 和 Kid_id,重要的是当我向这两个字段添加条目时:

kids.add(apple);
apple.add(kids);

Buckets 表中只有一条记录,而不是两条!如果您尝试使用 List<> 代替 Set<>(又名 unique),这一点非常重要。

于 2015-01-09T21:20:59.807 回答
0

如果您使用相同的catVerb_id@JoinColumn

@JoinColumn(name="catVerb_id", nullable = true) 

尝试将其更改为

@JoinColumn(name="catVerb_id", insertable = false, updatable = false) 

它不能为空,因为它是您的主键。

于 2013-06-07T01:29:05.090 回答