Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 休眠-至少有一个孩子_Java_Hibernate - Fatal编程技术网

Java 休眠-至少有一个孩子

Java 休眠-至少有一个孩子,java,hibernate,Java,Hibernate,这个问题有点问我想要实现什么,但实际上没有答案: 我有两个对象(A和B)。A是父母。B是孩子。这是一个一对多的关系,但是,我需要每个a始终至少有一个B。B中的所有字段都有默认值,因此如果创建a时没有B,则可以添加默认B以确保始终有一个B。如果添加一个或多个B对象a,则无需创建默认B 这是一个: [Fields] @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "key", nullab

这个问题有点问我想要实现什么,但实际上没有答案:

我有两个对象(A和B)。A是父母。B是孩子。这是一个一对多的关系,但是,我需要每个a始终至少有一个B。B中的所有字段都有默认值,因此如果创建a时没有B,则可以添加默认B以确保始终有一个B。如果添加一个或多个B对象a,则无需创建默认B

这是一个:

[Fields]

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "key", nullable = false)
@Fetch(value = FetchMode.SUBSELECT)
private List<B> b = new ArrayList<>();

...

@PrePersist
protected void onCreate() {
    // Default values configured here, for example
    if (fieldA1 == null) {
        fieldA1 = "A DEFAULT";
    }
    ...
}
我想我可以在A中使用相同的@PrePersist注释,检查是否有任何B对象,如果没有,则创建默认B:

@PrePersist
protected void onCreate() {
    // Deafult values configured here
    ...
    if (b.size() == 0) {
        b.add(new B());
    }
}
那不行。如果我创建了一个没有B对象的A,那么在日志中我只得到:

删除处理中瞬态实体的处理

而A是在没有B的情况下创建的。如果我尝试使用至少一个B创建A,则会出现以下错误:

原因:org.hibernate.transientObject异常:对象引用 未保存的临时实例-在之前保存临时实例 冲洗


你知道我该怎么做吗

在不了解更多代码的情况下(不管怎么说,这可能有点太多),我不得不做一些假设,但我要说的是,当调用
onCreate()
时,Hibernate会话已经处于“刷新”状态,因此不会接受任何新实体

目前,我可以想出两种方案,在某些情况下我们也会用到:

  • 一旦当前事务成功完成,抛出CDI事件并让事件处理程序(异步)触发在新事务中创建默认元素

  • 在Hibernate中创建一个子会话,该子会话从当前会话派生并使用相同的事务。然后使用此子会话创建默认元素

  • 下面是我们如何在Hibernate
    PostInsertEventListener
    中执行此操作:

    if( postInsertEvent.getEntity() instanceof ClassThatNeedsToBeHandled ) {
      ClassThatNeedsToBeHandled insertedEntity = (ClassThatNeedsToBeHandled )postInsertEvent.getEntity(); 
      Session subSession = postInsertEvent.getSession().sessionWithOptions()
        .connection() //use the same connection as the parent session                  
        .noInterceptor() //we don't need additional interceptors
        .flushMode( FlushMode.AUTO ) //flush on close
        .autoClose( true) //close after the transaction is completed
        .autoJoinTransactions( true ) //use the same transaction as the parent session
        .openSession();
    
      subSession.saveOrUpdate( new SomeRelatedEntity( insertedEntity ) );
    }
    
    需要记住的一点是,我们的
    SomeRelatedEntity
    是关系的所有者。您的代码表明
    A
    将是所有者,但这可能会导致问题,因为您必须在flush期间更改
    A
    实例以保持关系。如果
    B
    是拥有方(它有一个对
    a
    的反向引用,并且在
    a
    中,您的
    @OneToMany
    中有一个
    映射,它应该可以工作

    编辑:


    实际上,可能还有第三种选择:当您创建一个新元素时,添加一个默认元素,当添加真实元素时,删除它。这样,您就不必处理Hibernate会话或事务作用域。

    顺便说一句,我想推荐您提出这个问题。很少有新的投稿人在他们的问题上投入这么多精力。@Thomas,谢谢你的好话。这可能是我的第一个问题,但我已经在这里潜伏了很多年:)我看到了好的问题和坏的问题,这有助于了解如何最好地组织它。第三个选项是我首先想到的,因为这不应该给hibernate部分增加任何复杂性(有时可能会很棘手)@XtremeBaumer哦,是的,它可以:)谢谢你解释我为什么看到这些消息/错误。有道理。我试图在hibernate级别拦截缺少子对象的情况,因为这似乎是有意义的,特别是因为我已经在@PrePersist中设置了默认值。你的第三个选择无疑是一条路要走,因为似乎没有一个简单的hibernate方法来解决这个问题。我已经实现了您的建议,在rest控制器中创建默认子对象效果很好。
    if( postInsertEvent.getEntity() instanceof ClassThatNeedsToBeHandled ) {
      ClassThatNeedsToBeHandled insertedEntity = (ClassThatNeedsToBeHandled )postInsertEvent.getEntity(); 
      Session subSession = postInsertEvent.getSession().sessionWithOptions()
        .connection() //use the same connection as the parent session                  
        .noInterceptor() //we don't need additional interceptors
        .flushMode( FlushMode.AUTO ) //flush on close
        .autoClose( true) //close after the transaction is completed
        .autoJoinTransactions( true ) //use the same transaction as the parent session
        .openSession();
    
      subSession.saveOrUpdate( new SomeRelatedEntity( insertedEntity ) );
    }