使用 optional=false 进行一对一延迟加载,但如何使用 null 保存关联的子对象

Posted

技术标签:

【中文标题】使用 optional=false 进行一对一延迟加载,但如何使用 null 保存关联的子对象【英文标题】:One-to-one lazily load with optional=false but how to save associated subobject with null 【发布时间】:2016-06-30 11:01:04 【问题描述】:

首先,让我描述一下相关的两个类:

@Entity
@Table(catalog = "db_consumer_master", name = "t_consumer")
@PrimaryKeyJoinColumn(name = "id")
public class Customer
    @OneToOne(mappedBy = "customer", cascade = CascadeType.ALL, fetch =   FetchType.LAZY, optional = false)
    public CustomerWallet getWallet() 
        return wallet;
    



public class CustomerWallet 
    @Id
    @Column(name = "customer_id", unique = true, nullable = false)
    @GeneratedValue(generator = "gen")
    @GenericGenerator(name = "gen", strategy = "foreign", parameters=@Parameter(name = "property", value = "customer"))
    private long customerId;
    private long amount;

    @OneToOne
    @PrimaryKeyJoinColumn
    private Customer customer;

为了开启延迟加载,只设置fetch = FetchType.LAZY是不行的,所以我添加了“optional = false”,但是现在又出现了新的问题:

我想通过调用 session.save(lawyer) 创建一个新的 Lawyer 对象。这是创建律师实例的代码sn-p:

Customer customer= new Customer();
CustomerWallet wallet = new CustomerWallet();
customer.setWallet(wallet);

调用 save(customer) 时,抛出异常:

IdentifierGenerationException: 试图从空的一对一属性分配 id

所以,我的问题是,如何在钱包对象为 null 的情况下保存此客户对象?钱包需要一个客户 ID 作为关联的共享主键。但是在客户被持久化到数据库之前,我们不会得到这个客户 ID。我是否需要在 java 而不是数据库系统中生成 ID?这种情况还有其他选择吗?

【问题讨论】:

不应该被映射为customer ?什么是生成器“gen”?我觉得应该是“洋” 您需要 CustomerWallet 类中的属性律师 我认为@PrimaryKeyJoinColumn for field customer in CustomerWallet 是错误的,因为它不是 CustomerWallet 类的主键 "gen" 是 id 生成器的名称。我在别处借的。 【参考方案1】:

要启用延迟加载,仅设置 fetch = FetchType.LAZY 不起作用,所以我添加了“optional = false”

optional 属性不能强制延迟加载。它在 JPA 2.0 规范中定义如下:

(可选)关联是否可选。如果设置为 false,则必须始终存在非空关系。

以下是规范中对延迟加载的说明:

(可选)关联是应该延迟加载还是必须急切获取。 EAGER 策略是对持久性提供程序运行时的要求,即必须急切地获取关联实体。 LAZY 策略是对持久性提供程序运行时的提示。

这意味着持久性提供者没有义务延迟加载关联的实体。

现在回答你的问题:

所以,我的问题是,如何保存这个钱包对象为空的客户对象?

    首先正确定义映射 您在与Customer 的关联上使用PrimaryKeyJoinColumn 注释。此注解用于在 JOINED 映射策略中将子类连接到其父类。但是在您的情况下,您的实体没有继承关系。所以你必须改用 JoinColumn 注释:

    @OneToOne
    @JoinColumn(name = <name_of_foreign_key>) (Optional)
    private Customer customer;
    

    Customer 类中的@OneToOne 注释中删除optional = false

    您的foreign key 列必须允许NULL 值。否则,你会得到引用约束冲突异常。

【讨论】:

非常感谢 ujulu。数据库架构是使用 java 类中的 hibernate4-maven-plugin 生成的,因此每次生成架构时都会更改“name_of_foreign_key”。这种情况如何处理? 顺便说一下,@PrimaryKeyJoinColumn 可用于将 User 类中的 shippingAddress 映射为共享主键关联。摘自 第 281 页。 在这种情况下,JoinColumn 是可选的,您可以从注释中删除(请参阅上面的修改后的帖子)。 PrimaryKeyJoinColumn 所关注的内容参见Hibernate documentation。顺便说一句,我没看过那本书。

以上是关于使用 optional=false 进行一对一延迟加载,但如何使用 null 保存关联的子对象的主要内容,如果未能解决你的问题,请参考以下文章

@OneToOne(optional=false) 和 @JoinColumn(nullable=false) 一起使用

MyBatis一对多查询及延迟加载

Mybatis 是否支持延迟加载?如果支持,它的实现原理是 什么?

Mybatis 是否支持延迟加载?如果支持,它的实现原理是 什么?

@Basic(optional = false) vs @Column(nullable = false) vs @NotNull

过一下hibernate4-6(含Log4J)