Hibernate OneToMany完整性约束违规:外键没有父项。

4

我想为学校写一个简单的项目,但是我有一个问题无法解决。我在Stack Overflow上搜索了解决方案,但是没有一个真正起作用的。所以问题是:

我使用Hibernate创建了两个实体类(我的数据库是HSQLDB):

@Entity
@Table(name = "Zwierzak")
@NamedQueries({ @NamedQuery(name = "delZwierzak", query = "Delete from Zwierzak z where z.zwierzakId = :zid"),
                @NamedQuery(name = "delAll", query = "Delete from Zwierzak"),
                @NamedQuery(name = "getAll", query = "from Zwierzak"),
                @NamedQuery(name = "getByGatunek", query = "Select z from Zwierzak z where z.gatunek = :g")})

public class Zwierzak {

//Some fields here ...

@OneToMany(fetch = FetchType.EAGER, mappedBy = "chorobaId", cascade = {javax.persistence.CascadeType.ALL}, orphanRemoval = true)
@Cascade({org.hibernate.annotations.CascadeType.ALL})
private Set<Choroba> choroby = new HashSet<Choroba>(0);

//Some methods here ...

其次是二等舱:

@Entity
@Table(name="Choroba")
public class Choroba {

    //Some fields here ...

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name="zwierzakId")
    @OnDelete(action = org.hibernate.annotations.OnDeleteAction.CASCADE)
    Zwierzak zwierzak;

    //Some methods here ...

现在我正在向数据库添加一些动物实体,尝试这样添加疾病:

现在我向数据库添加一些Zwierzak实体,并尝试以此方式添加Choroba:

Session session = sessionFactory.getCurrentSession();
    session.beginTransaction();

            //Creating and saving Zwierzak (parent) first
    Zwierzak z = new Zwierzak();
    session.save(z);

            //Creating choroba
    Choroba ch = new Choroba();
            //Setting parent in child class
    ch.setZwierzak(z);
            //Adding child in parent class
    z.getChoroby().add(ch);
            //Saving child
    session.save(ch);

我仍然遇到异常。以下是来自日志的堆栈跟踪:

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.673 sec <<< FAILURE!
addZwierzakTest(pl.ug.edu.pl.services.ZwierzakServiceTest)  Time elapsed: 0.249 sec  <<< ERROR!
org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:74)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:136)
    at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:96)
    at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:58)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2975)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3487)
    at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:81)
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:377)
    at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:214)
    at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:194)
    at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:178)
    at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:321)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:286)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:192)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:206)
    at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:191)
    at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
    at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:764)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:756)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:752)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:352)
    at com.sun.proxy.$Proxy17.save(Unknown Source)
    at pl.ug.edu.pl.services.ZwierzakService.dodajChorobe(ZwierzakService.java:50)
    at pl.ug.edu.pl.services.ZwierzakServiceTest.addZwierzakTest(ZwierzakServiceTest.java:45)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:292)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: java.sql.SQLIntegrityConstraintViolationException: integrity constraint violation: foreign key no parent; FK_Q70JGX265MYFNVPD1K5M8ONUD table: CHOROBA
    at org.hsqldb.jdbc.Util.sqlException(Unknown Source)
    at org.hsqldb.jdbc.Util.sqlException(Unknown Source)
    at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.JDBCPreparedStatement.executeUpdate(Unknown Source)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)
    ... 58 more

我不知道出了什么问题,尝试了很多看起来可以解决这个问题的方法,但是还是不行,我不知道哪里出错了。如果能得到一点帮助就非常感激,谢谢!

编辑:当然,id是由@Id注释生成的。


你的 mappedBy = "chorobaId" 看起来是错误的。应该是 mappedBy="zwierzak" - RP-
2个回答

4
我认为问题在于保存操作不会在提交时创建ID,因此当您尝试进行第二次保存时,ID不存在,请在第二次保存之前考虑刷新(flush)。
 Zwierzak z = new Zwierzak();
    session.save(z);

   !!!Consider a flush here !!!
   session.flush();

            //Creating choroba
    Choroba ch = new Choroba();
            //Setting parent in child class
    ch.setZwierzak(z);
            //Adding child in parent class
    z.getChoroby().add(ch);
            //Saving child
    session.save(ch);

此外
@OneToMany(fetch = FetchType.EAGER, mappedBy = "chorobaId", 

我们应该

@OneToMany(fetch = FetchType.EAGER, mappedBy = "zwierzak",

Mapped by指的是包含@ManyToOne注解类型的字段,而不是直接使用id。这应该可以解决问题。


即使使用flush也无法工作。我甚至尝试提交父级保存,关闭会话,然后再次打开它,然后保存子级(在从数据库获取父级、设置它等之后...),但仍然出现相同的错误。 - user2759804
1
你尝试过将ManyToOne和OneToMany设置正确吗?我认为这就是问题所在,请查看我的回复更新。 - Koitoer
这很有效。我对此还很陌生,不太清楚它是如何工作的,但它确实有效。我会花些时间去学习更多,但现在我有点忙,所以非常感谢你的帮助! :) - user2759804

0
在我的情况下,@OneToMany集合被更新了,一些项目被删除了,新的项目被添加了。尽管在集合上指定了orphanremoval=true,但Hibernate实际上并没有从数据库中删除这些条目。异常是在尝试删除拥有实体时抛出的。
解决方法是在更新操作期间明确地从数据库中删除这些项目。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接