【问题标题】:Hibernate One to Many Mapping is trying to update mapping column to null休眠一对多映射正在尝试将映射列更新为空
【发布时间】:2014-08-20 16:35:19
【问题描述】:

我正在使用下面的映射

@Entity
@Table(name = "test")
public class TestOrder implements Serializable {

    @Id
    @Column(name = "orderid", updatable = false)
    protected Long orderId;

    @OneToMany(cascade = {CascadeType.ALL})
    @JoinColumn(name = "order_id_fk")
    private List<TestDetails> details;

//getters and setters
}

@Entity
@Table(name="test_details")
public class TestDetails implements Serializable {

    @Id
    //Generator
    @Column(name = "id", updatable = false, insertable = false)
    protected Long id;

    @Column(name="order_id_fk", updatable = false)
    private Long orderId;
//getters and setters
}

当我更新/插入数据时,它会尝试将 order_id_fk 更新为 null

SQL [update test_details set order_id_fk'='null where order_id_fk'='? and id'='?]; constraint [null];

非常感谢任何帮助。

使用 Spring 集成更新/插入

<int-jpa:updating-outbound-gateway entity-class="com.aaaa.TestOrder" entity-manager-factory="myEntityManagerFactory" persist-mode="MERGE">
    <int-jpa:transactional propagation="REQUIRED" transaction-manager="myTransactionManager" />
</int-jpa:updating-outbound-gateway>

【问题讨论】:

  • 你能粘贴代码DAO吗?
  • @Pracede,我正在使用 spring 集成来插入/更新。更新操作
  • 您是否在保存或更新之前设置了 TestOrder 及其属性详细信息?
  • @Pracede,是的。令人惊讶的是,它按预期首先插入数据。但之后它会尝试执行此更新查询
  • @ManyToOne 注释和mappedBy 哪里来?

标签: java spring hibernate jpa annotations


【解决方案1】:

您可能需要更改实体,如下所示。据我所知,如果您尝试设置列的外键,这效果最好。

@Entity
@Table(name="test_details")
public class TestDetails implements Serializable {

    @Id
    //Generator
    @Column(name = "id", updatable = false, insertable = false)
    protected Long id;

    @Column(name="order_id_fk", updatable = false, insertable = false)
    private TestOrder orderId;
//getters and setters
}

【讨论】:

  • 我认为你必须再试一次:) 这是完成它的正确方法。
【解决方案2】:

您需要急切地获取TestDetails 实体的值。

只需在注释中修改,

@OneToMany(fetch = FetchType.EAGER, mappedBy="testOrder", cascade=CascadeType.ALL)

希望这会奏效。

【讨论】:

  • 使用mappedBy 代替Join Column 的任何理由。因为Test Order 应该是所有者并且TestDetails 在其架构中有外键列[order_id_fk]
  • 还有一个疑问,如果我添加mappedBy,我必须将TestOrder 属性添加到TestDetailsManyToOne 关系。是否必须像我期望的那样建立双向关系。
  • 如果你使用了映射,那么休眠将知道需要获取哪些实体值。
  • 同意。但它也需要从另一侧映射[Test_details]。只是为了增加我的知识,是应该这样还是我最初的方法有缺陷?
  • 这里不需要加入列,因为参考模型对象你会得到testDetails的列表。只需确保在 TestDetails ManyToOne 关系中分配了 TestOrder。所以从 TestOrder 中删除 testDetails 的 JoinColumn 并将其更改为只有 oneToMany 关系。
【解决方案3】:

我运行了您的代码,它可以正常工作(将 @GeneratedValue(strategy = GenerationType.AUTO) 添加到两个 ID 时)。

em.getTransaction().begin();
TestOrder to = new TestOrder();
TestDetails td1 = new TestDetails();
TestDetails td2 = new TestDetails();
TestDetails td3 = new TestDetails();
to.setDetails(Arrays.asList(new TestDetails[] {td1, td2, td3}));
em.persist(to);
em.getTransaction().commit();

导致以下 sql 的结果:

[03/07/14 10:03:30]  INFO jdbc.sqlonly: insert into test (orderid) values (1) 
[03/07/14 10:03:30]  INFO jdbc.sqlonly: insert into test_details (order_id_fk, id) values (NULL, 2) 
[03/07/14 10:03:30]  INFO jdbc.sqlonly: insert into test_details (order_id_fk, id) values (NULL, 3) 
[03/07/14 10:03:30]  INFO jdbc.sqlonly: insert into test_details (order_id_fk, id) values (NULL, 4) 
[03/07/14 10:03:30]  INFO jdbc.sqlonly: update test_details set order_id_fk=1 where id=2 
[03/07/14 10:03:30]  INFO jdbc.sqlonly: update test_details set order_id_fk=1 where id=3 
[03/07/14 10:03:30]  INFO jdbc.sqlonly: update test_details set order_id_fk=1 where id=4

因此,如果您发布的代码是您编译的代码,则 TestOrder 实体无法生成其 ID(缺少 @GeneratedValue 注释)。

如果数据库为此实体生成 ID(即使用自动编号),您应该将 @GeneratedValue 设置为 IDENTITY 以让您的 jpa 提供者知道它必须在之后重新读取插入的行。如果 jpa 提供者无法重新读取 id,它会将 test_details order_id_fk 列更新为 null。

PS。为什么不在 TestDetails 端设置多对一的关系?

【讨论】:

  • 感谢您的努力。我会检查并更新你。关于TestDetails的多对一,有必要吗?因为我确实看到了一些循环依赖和我在 Hibernate 中的知识问题:)
  • 这不是必需的,它会让您记住更新关系的双方 (testOrder.setDetails(testDetails); testDetails.setOrder(testOrder))。但它允许您简单地从 testDetails 实例导航到 testOrder 之一(通过testDetails.getOrder())。您可能会遇到循环依赖错误,因为双向关系一侧应该是反向的(这个没有带有外键的列)。可以通过在 @OneToMany 注释中添加 mappedBy 属性来标记反面。
  • 我浏览了庞大的代码库,发现它从其他表temp_order 获取order_id。简而言之,在temp_order 表中创建的第一个订单将与idorder 表中使用相同
猜你喜欢
  • 2023-03-14
  • 2011-04-07
  • 1970-01-01
  • 2019-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-07
相关资源
最近更新 更多