无法在 HIbernate 4 中保持 OneToMany 关系

Posted

技术标签:

【中文标题】无法在 HIbernate 4 中保持 OneToMany 关系【英文标题】:Unable to persist OneToMany relationship in HIbernate 4 【发布时间】:2012-09-18 12:19:35 【问题描述】:

在使用休眠模式获取一些数据时遇到问题

我声明了两个独立的类,License 和 MacAddress。 MacAddress 可以单独存在,但也可以链接到许可证,当 hibernate 生成基础表时,它会创建一个 License、MacAddress 和 License_MacAddress 表。

许可证

@Entity
public class License

    @Id
    @GeneratedValue
    private Integer      id;

    @Column(nullable = false)
    private String      license;

    @OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
    private
    List<MacAddress> macAddresses;

    public Integer getId()
    
        return id;
    

    public void setId(Integer id)
    
        this.id = id;
    

    public String getLicense()
    
        return license;
    

    public void setLicense(String license)
    
        this.license = license;
    

    public List<MacAddress> getMacAddresses()
    
        return macAddresses;
    

    public void setMacAddresses(List<MacAddress> macAddresses)
    
        this.macAddresses = macAddresses;
    

Mac地址

@Entity
public class MacAddress

    @Id
    @GeneratedValue
    private Integer      id;

    @Column(nullable = false)
    private String      macAddress;


    public Integer getId()
    
        return id;
    

    public void setId(Integer id)
    
        this.id = id;
    

    public String getMacAddress()
    
        return macAddress;
    

    public void setMacAddress(String macAddress)
    
        this.macAddress = macAddress;
    

我想要做的是以下。

在某些时候会创建一个新的许可证,并在许可证表中存储一行(这可以正常工作)

然后在稍后的时间收到用户的许可证和 MAC 地址。从数据库中检索许可证,我们检查提供的 macAddress 是否已经与许可证相关联(多个 macaddress 可以与许可证相关联),如果没有,我们想要存储 macaddress 以及许可证和 macaddress 之间的链接。

但是,尽管在 License 的 @OneToMany 注释上设置了 CascadeType.ALL,但没有存储任何 Mac 地址信息。我可以通过单独保存该对象来手动保存 MacAddress,但 License_MacAddress 表仍然为空。

代码

session = Db.getSession();
License license = getLicense(session, licenseStr);
List<MacAddress> macAddresses = license.getMacAddresses();
for(MacAddress mac:macAddresses)

    if(mac.getMacAddress().equals(macAddress))
    
        return;
    


MacAddress mac = new MacAddress();
mac.setMacAddress(macAddress);
session.save(mac);
license.getMacAddresses().add(mac);
session.saveOrUpdate(license);
return;

为什么我不能让两者之间的关系持久化?

【问题讨论】:

【参考方案1】:

将更改保存到数据库时,Hibernate 会遵循 Unit of Work pattern。

您打开一个工作单元,将更改应用于与其关联的对象,当您关闭该工作单元时,Hibernate 会自动保存您的更改。

在Hibernate API的实际使用中,工作单元的概念通常与Hibernate事务相匹配,因此在这种情况下你需要一个事务:

session = Db.getSession(); 
Transaction tx = null; 
try  
    tx = session.beginTransaction(); 
    License license = getLicense(session, licenseStr); 
    List<MacAddress> macAddresses = license.getMacAddresses(); 
    for(MacAddress mac:macAddresses) 
     
        if(mac.getMacAddress().equals(macAddress)) 
         
            return; 
         
     

    MacAddress mac = new MacAddress(); 
    mac.setMacAddress(macAddress); 
    license.getMacAddresses().add(mac);     
    tx.commit(); 
 catch (RuntimeException e)  
    if (tx != null) tx.rollback(); 
    throw e; // or display error message 
 finally  
    session.close(); 

另请参阅:

13.1.1. Unit of work

【讨论】:

谢谢,完全忘记了事务,我认为这是因为我的 createLicense 方法也没有使用事务并且工作我猜它有效,因为它只更新了一个实体和表,而 Hibernate 创建了这个简单案例的隐含交易?

以上是关于无法在 HIbernate 4 中保持 OneToMany 关系的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate创建没有关系表的关系

hibernate one2one

JPA 中的 @Any 等价于啥?

如何在不使用 JPA 的情况下保持在 SpringBoot/GraphQL 中打开的 Hibernate 事务?

Hibernate 中无法自动创建表的解决办法

Hibernate 4无法为当前线程获取事务同步会话