【问题标题】:How does Hibernate work with @OneToOne and Cascade.ALL? (using Spring)Hibernate 如何与@OneToOne 和 Cascade.ALL 一起工作? (使用弹簧)
【发布时间】:2015-06-18 11:26:14
【问题描述】:

我有一个类 Customer,它与 Subscription 具有 OneToOne 双向关系:

@Entity
@Table(name = "customers")
public class Customer{
    @OneToOne(mappedBy="customer",cascade = CascadeType.ALL)
    private Subscription currentSubscription;
}

@Entity
@Table(name = "subscriptions")
public class Subscription {

    @Id
    @Column(columnDefinition = "INT8",name="id", unique=true, nullable=false)
    @GeneratedValue(generator="gen")
    @GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="customer"))
    private Long id;

    @OneToOne
    @PrimaryKeyJoinColumn
    private Customer customer;
}

现在,当我创建一个带有订阅的客户并在该客户上调用 persist 时,它很好地将订阅保存到数据库中。但是,当我已经保留了一个客户并想要添加订阅时,它会失败并出现以下错误:

引起:org.hibernate.id.IdentifierGenerationException:尝试 从 null 一对一属性分配 id [com.qmino.miredot.portal.domain.Subscription.customer]

我写了一个测试来解释我想要实现的目标:

@Test
public void shouldCascadeUpdateSubscription(){
    Customer owner = customerRepository.save(CustomerMother.getCustomer(false));

    Subscription subscription = SubscriptionBuilder.create()
            .setBillingDayOfMonth(LocalDate.now().getDayOfMonth())
            .setSubscriptionPlan(subscriptionPlan)
            .build();

    subscription.setCustomer(owner);
    owner.setCurrentSubscription(subscription);

    customerRepository.save(owner);

    Customer result = customerRepository.findOne(owner.getId());
    assertThat(result.getCurrentSubscription(),is(notNullValue()));
    assertThat(result.getCurrentSubscription().getId(),is(result.getId()));
}

我哪里做错了?

【问题讨论】:

  • 你说实体是双向链接的吗?它看起来不像。您的订阅没有客户。所以 'mappedBy="customer" ' 是多余的。
  • 我的错,出错了。现在应该是正确的。
  • subscription.setAccountDetails(owner);为什么不遵循 EJB 规范? Hibernate 应该有一个合适的 setter/getter。所以“setAccoundDetails”应该是“setCustomer”/“getCustomer”
  • 再次出错,我错误地输入了错误的类,并且忘记了setter。我很抱歉。
  • 那么parameters=@Parameter(name="property", value="accountDetails" 也应该是客户?请改正所有错别字

标签: java hibernate jpa spring-data one-to-one


【解决方案1】:

这里的级联不是问题,级联表示删除或更新时实体要执行的操作。如果要保存完整的实体,什么是正确的。但是为此,您需要拥有正确的数据,您的消息建议它尝试更新Customer 实体但它发现了一个空的AccountDetails,因此为了正确获取其他实体,您需要添加FecthType.EAGER , 获取映射实体的所有属性。

@OneToOne(mappedBy="customer",cascade = CascadeType.ALL, fetch = FetchType.EAGER))

【讨论】:

  • 我应该澄清一下,我得到的错误发生在所有者的第二次保存中。我只是在测试快结束时才得到一个客户,问题发生在此之前。
  • FetchType.EAGER 的缺点是您将对关系进行单独的选择查询。有时可能是个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-02
  • 1970-01-01
相关资源
最近更新 更多