java JPA 使用父级合并但创建了子级时,如何获取生成的 id/对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17816196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 15:05:59  来源:igfitidea点击:

JPA How can I get the generated id/object when using merge from parent but child is created?

javajpa

提问by Ioannis Deligiannis

I have an entity that has been previously persited and has a @OneToManyrelationship with another entity. In order to add a new entity I just add my new entity in the managed object and use cascadeType.ALLto persist the changes. Is there a way that I can get the id's of the newly created objects or get the original (unmanaged) object I used with the merge to have its id updated?

我有一个实体,该实体之前已被持久化并@OneToMany与另一个实体有关系。为了添加一个新实体,我只需在托管对象中添加我的新实体并用于cascadeType.ALL持久化更改。有没有办法可以获取新创建对象的 id 或获取与合并一起使用的原始(非托管)对象以更新其 id?

In pseudo-code I would expect the following to happen:

在伪代码中,我希望发生以下情况:

  1. New copy is going to be returned for merged entity
  2. Old copy is going to be update for new entities
  1. 将为合并的实体返回新副本
  2. 旧副本将针对新实体进行更新

Example: Parent A, id=13 Child B, id=0

示例:父 A,id=13 子 B,id=0

In essence, I want to issue a mergeon the parent but cascade persiston child (so that the original child instance is updated, not copied).

本质上,我想merge在父级persist上发出 a但在子级上级联(以便更新原始子实例,而不是复制)。

Obviously this doesn't happen. I am using hibernate as the provider.

显然这不会发生。我使用休眠作为提供程序。

采纳答案by Ioannis Deligiannis

Stackoverflow postand JPA documentationhave the answer provided that you do your research.

只要您进行研究,Stackoverflow帖子JPA 文档就有答案。

The way to do what I want is to use persiston the managedparent. This will ignore any changes on the parent, but will cascade persist(provided that it is set up to cascade). The child object will have the correct id afterwards.

做我想做的方法是persist托管的父级上使用。这将忽略父级上的任何更改,但会级联persist(假设它设置为级联)。之后子对象将具有正确的 id。

....
JPAEntity newObject=new JPAEntity();
managedObject.addChild(newObject);
em.persist(managedObject)
newObject.getId() //work fine!

回答by Felix

I had a similar problem with persistence provider eclipselink. I needed to add new orders from a client database with temporary "client orderIDs" to an existing customer in a server database. Because I needed the "server orderIDs" for further client requests, i wanted to create a map (clientID, serverID) and send it back to the client. Basically my approach is to get a reference to the copy of the newly added child order. It will always be added to the end of my list in parent class customer, that fact is used to retrieve it.

我在持久性提供程序 eclipselink 上遇到了类似的问题。我需要将带有临时“客户端订单 ID”的客户端数据库中的新订单添加到服务器数据库中的现有客户。因为我需要进一步的客户端请求的“服务器 orderID”,所以我想创建一个映射(clientID、serverID)并将其发送回客户端。基本上我的方法是获取对新添加的子订单副本的引用。它将始终添加到父类客户列表的末尾,该事实用于检索它。

I use the entity classes Customer and Order, where Customer has a List (LinkedList) of orders.

我使用实体类 Customer 和 Order,其中 Customer 有一个订单列表 (LinkedList)。

Parent Customer class: ...

父客户类:...

    @OneToMany(mappedBy = "customer", cascade=CascadeType.ALL, orphanRemoval = true)
    private List<Order> orders = new LinkedList<Order>();

    public Order getLastOrder() {
      return orders.get(orders.size()-1);
    }

Child Order class:

子订单类:

    @ManyToOne(optional=false)
    private Customer customer;

Servlet:

服务端:

    Customer customer = customerService.findByID(customerID); //existing customer
    Order order = new Order();
    //add attributes to new order
    customer.addOrder(order);
    customerService.update(customer); //generates keys for children
    order = customer.getLastOrder();
    Long orderID = order.getID; //Nullpointer exception

CustomerService updates customer with EntityManager.merge but I forgot to update the reference in the servlet:

CustomerService 使用 EntityManager.merge 更新客户,但我忘记更新 servlet 中的引用:

CustomerService class:

客户服务类:

    public void update(Customer entity) {
      entityManager.merge(entity);
    }  

I solved it this way: CustomerService class:

我是这样解决的:CustomerService 类:

    public Customer update(Customer entity) {
      return entityManager.merge(entity);
    }

Servlet: ....

小服务程序:....

    customer = customerService.update(customer); //generates keys for children

Now everything works fine.

现在一切正常。

回答by Richard Sitze

You should be able to "see" a generated ID for a new Entity:

您应该能够“看到”为新实体生成的 ID:

  • after transaction commits, or

  • after a em.flush()(where emis your EntityManager) while a transaction is active.

  • 事务提交后,或

  • 在交易处于活动状态时em.flush()em您的在哪里EntityManager)之后。

Note also that allrelationships between Entities need to be resolved in the Java data structures prior persistence. Child references to parents need to be "set", and vice-versa.

另请注意,实体之间的所有关系需要在持久化之前在 Java 数据结构中解决。孩子对父母的引用需要“设置”,反之亦然。

回答by Anthony Accioly

Make sure that you are setting both sites of the relationship before persisting the changes.

确保在保留更改之前设置关系的两个站点。

child.setParent(parent);
parent.getChildren().add(child);
Parent parentWithId = em.merge(parent);
em.flush(); // make sure that the persistence context and database are in sync
parentWithId.getId(); // works
parentWithId.getChildren().get(0).getId(); // should also work