@OneToMany @ManyToOne двунаправленный объект не будет правильно принимать новый объект (GlassFish)

#jpa #glassfish #entity #one-to-many #duplicates

#jpa #glassfish #объект #один ко многим #дубликаты

Вопрос:

старое описание проблемы устарело

@unwichtich спасибо за ваш совет, он помог избавиться от этой неприятной ошибки.

У меня есть объекты:

 @Entity
@XmlRootElement
@Table(name="WAITERENTITY")
public class WaiterEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.EAGER)
    @JoinColumn(name = "waiter_id")
    private List<OrderEntity> orders = new ArrayList<>();

    {plus usual setters and getters}
}
  

и

 @Entity
@XmlRootElement
@Table(name="ORDERENTITY")
public class OrderEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long orderNumber;

    @ManyToOne (cascade = CascadeType.ALL)
    @JoinColumn (name = "table_id")
    private TableEntity table_;

    private int sumOfMoney = 0;

    private boolean finalized = false;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id")
    private List<OrderItemEntity> orderItems = new ArrayList<>();

    @ManyToOne (cascade = CascadeType.ALL)
    @JoinColumn (name = "waiter_id")
    private WaiterEntity waiter;

    {plus usual setters and getters}
}
  

Но основная проблема остается. В базе данных все так, как должно быть:

 <waiterEntities>
   <waiterEntity>
      <id>9</id>
      <name>Jack Marston #499</name>
   </waiterEntity>
   <waiterEntity>
      <id>10</id>
      <name>Abigail Marston</name>
   </waiterEntity>
</waiterEntities>

<orderEntities>
   <orderEntity>
      <finalized>false</finalized>
      <orderNumber>12</orderNumber>
      <sumOfMoney>0</sumOfMoney>
      <waiter>
         <id>9</id>
         <name>Jack Marston #499</name>
      </waiter>
   </orderEntity>
</orderEntities>
  

Но @OneToMany отношение WaiterEntity возвращает только пустой список при waiter.getOrders() вызове.

Метод, который создает новый OrderEntity , следующий:

 public void create(OrderEntity e) {
    WaiterEntity waiter = em.find(WaiterEntity.class, e.getWaiter().getId());
    if (waiter != null) {
(1)     e.setWaiter(waiter);
        em.persist(e);
        System.out.println("after persist:n"   e);
(2)     //waiter.getOrders().add(e);
(3)     //em.merge(waiter);
    }
}
  

Редактировать: я наблюдал очень странное поведение. Во-первых, если строки, отмеченные (2) и (3) , не прокомментированы, OrderEntity вообще не будут сохраняться. Во-вторых, только следующих внешних операторов будет достаточно, чтобы GlassFish сохранял OrderEntity :

 WaiterBean waiter = client.findByNameSingle(WaiterBean.class, "John Marston");
client.create(new OrderBean(waiter));
  

Где create получит уникальный идентификатор соответствующего WaiterEntity объекта из базы данных. С другой стороны, an OrderEntity не будет сохранен, если WaiterEntity идентификатор не известен, как, например, в:

 client.create(new OrderBean(new WaiterBean("Hans")));
  

потому что этот новый объект не получен из базы данных. При закомментировании строки, отмеченной (1), появляется поведение strage: первый оператор с предыдущим получением соответствующего WaiterEntity из базы данных не будет работать, но второй оператор, который не получает ничего WaiterEntity из базы данных, будет работать и создаст OrderEntity запись в базе данных. Мне действительно трудно это понять.

Две прокомментированные строки (2) и (3) должны гарантировать, что WaiterEntity он знает свои OrderEntity s для последующего извлечения. Но единственное, что делают эти две строки (или одна из них, я тоже пробовал), это предотвращение сохранения любого OrderEntity объекта в базе данных. Он просто ничего не сделает, и никаких дальнейших ошибок не сообщается, что сводит меня с ума…

Есть идеи? Заранее спасибо!

Ответ №1:

Просто предположим, что вы добавляете неправильный OrderEntity экземпляр. Если вы передаете экземпляр объекта em.merge() EntityManager в, создается новый экземпляр вашего объекта, копирует состояние из предоставленного объекта и делает новую копию управляемой. Вы должны использовать новую копию в любых дальнейших действиях в отношении этого объекта.

В коде:

 public void create(OrderEntity e) {
    WaiterEntity waiter = em.find(WaiterEntity.class, e.getWaiter().getId());
    e = em.merge(e);
    if (waiter != null) waiter.getOrders().add(e);
}
  

Комментарии:

1. Спасибо! Это немного помогает. Я обновил описание своей проблемы.