jpa 为什么在双向一对一Map中使用外部生成策略时,实体会自动保存而不调用persist?

s6fujrry  于 2022-11-14  发布在  其他
关注(0)|答案(1)|浏览(110)

我一直在Hibernate中练习一对一的Map,但不理解这个特殊的例子。我必须说,程序运行得很好,正如我所期望的那样,但显然我可以省略一个perist()调用,它仍然运行得很顺利。它运行的事实是好的,但我想确切地知道为什么调用是可选的。让我写一些细节:
这是用户类,它应该是Map的拥有方:

@Data
@Entity
public class User {
    
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE)
    private Long id;
    
    private String name;
    
    @OneToOne
    private Ticket ticket;
    
    public User() {}
    
    public User(String name) {
        this.name=name;
    }
}

这是应该作为依赖项的票证类:

@Data
@Entity
public class Ticket {
    
    @Id
    @GeneratedValue(generator="foreignGenerator")
    @GenericGenerator(name="foreignGenerator", strategy="foreign", 
    parameters=@org.hibernate.annotations.Parameter(name="property", value="user"))
    private Long id;
    
    @OneToOne(optional = false, mappedBy="ticket")       
    @PrimaryKeyJoinColumn
    private User user;
    
    public Ticket() {
        
    }
    
    public Ticket(User user) {
        this.user=user;
    }   

}

我尝试在一对一Map中测试“共享主键”策略。如您所见,我已经使用外部策略设置了生成器,该策略应该使Ticket的id与其对应的User的id相同。

@Bean
    CommandLineRunner loadData() {
        return args->{
            EntityManager em=emf.createEntityManager();
            em.getTransaction().begin();
            User user=new User("Test User");
            Ticket ticket=new Ticket(user);
            //em.persist(user);
            user.setTicket(ticket);
            em.persist(ticket);
            em.getTransaction().commit();
            em.close();
            //We don't have to call persist on user
        };
    }       
}

这个程序运行得很好。取消注解在user上调用persist的行没有什么区别。我假设设置了user属性的persisting ticket也会自动保存用户。因此,没有区别的原因是,无论用户是否被保存,当我们调用ticket时,它都会被持久化。
我想知道我的假设是否正确,任何到文章/文档的额外链接都将非常感谢。特别是我想知道我上面说的这一部分-“我假设持久化票据,它有它的用户属性集,也会自动保存用户。”我找不到任何可以证实或否认这一点的信息。我知道一对一中的“共享主键”方法一个Map是“外来”生成策略的唯一用例,因此没有太多关于它的帖子,并且无论有什么帖子,在搜索期间都被“外来关键字”所掩盖。
任何关于这个问题的帮助或任何其他可能与上面提供的代码错误的问题将不胜感激。感谢您花时间阅读本文

hi3rlvi2

hi3rlvi21#

JPA规范指出此行为是错误的:
查看3.0版:“3.2.2.持久化实体示例”一节暗示用户在持久化之后是非托管的(您可以使用em.contains方法进行检查)。
“3.2.4.数据库同步”一节介绍了刷新/提交,其中规定:

• If X is a managed entity, it is synchronized to the database.
  ..
  ◦ For any entity Y referenced by a relationship from X, where the relationship to Y has not been annotated with the cascade element value cascade=PERSIST or cascade=ALL:
    ▪ If Y is new or removed, an IllegalStateException will be thrown by the flush operation (and the transaction marked for rollback) or the transaction commit will fail.

用户是新用户,所以这应该会导致异常。它的工作可能是Hibernate处理@PrimaryKeyJoinColumn注解(我的推测)和自定义“foreignGenerator”的方式中的一个小故障。
我建议您不要依赖这种模式,而应该调用persist来避免与其他Map设置的行为不一致。

相关问题