2017-02-12 34 views
0

В моем заявлении у меня есть тендер.Как работает операция слияния с отношениями «один ко многим» - JPA

@Entity 
    @Table(name = "tender") 
    public class Tender { 

     @Id 
     @Column(name = "tender_id", unique = true, nullable = false) 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     private long id; 

     @Column(name = "name") 
     private String name; 

     @Column(name = "description") 
     private String description; 

     @OneToMany(mappedBy="tender", cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
     @JsonIgnoreProperties("tender") 
     private List<TenderAddress> addresses; 

     // constructors and getters and setters 
     // I am showing the setter for Address since it is customized for my requirement 

     public void setAddresses(List<TenderAddress> addresses) { 
      this.addresses = addresses; 
      for (TenderAddress tenderAddress : addresses) { 
      tenderAddress.setTender(this); 
      } 
     } 

    } 

Объект My TenderAddress выглядит следующим образом.

@Entity 
@Table(name = "tender_address") 
public class TenderAddress { 

    @Id 
    @Column(name = "id", unique = true, nullable = false) 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private long id; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name="tender_id") 
    @JsonIgnoreProperties("addresses") 
    private Tender tender; 

    @Column(name = "address", nullable = false) 
    private String address; 

    // constructors 
    //getters and setters 
} 

Все работало нормально, пока я не начал тестирование операции обновления.

Это мой метод обновления.

@Transactional 
    public Tender updateTender(Tender tender) { 
     Tender t = entityManager.find(Tender.class, tender.getId()); 

     t.setName(tender.getName()); 
     t.setDescription(tender.getDescription()); 

     t.setAddresses(tender.getAddresses()); 

     entityManager.merge(t); 
     entityManager.flush(); 
     return findById(t.getId()); 
    } 

имя и описание обновляются в порядке. То, что я подумал о том, как будут обновляться адреса, - это отредактировать текущую запись в соответствующей таблице базы данных. Но произошло то, что он вставил новую запись в таблицу без редактирования уже существующей записи. На самом деле, я думал, что JPA заботится об этом.

Итак, теперь мой вопрос: я должен явно объединить таблицу адресов при слиянии тендерной таблицы? Если да, то как это должно быть сделано?

+0

Когда вы вызываете 'updateTender', откуда берутся записи в списке' tender.addresses'? У них есть свои исходные идентификаторы?Если нет, JPA не может знать, что они должны рассматриваться как существующие объекты. – crizzis

+0

@crizzis эти адреса заданы в классе контроллера. Это в DAO. Я не устанавливаю идентификаторы для адресных объектов. Но идентификатор тендера для них устанавливается с использованием метода setter, когда я вызываю 't.setAddresses (tender.getAddresses)'. Должен ли я устанавливать идентификаторы для объектов Address? – vigamage

+0

Вы должны просто не потерять информацию об идентификаторах существующих адресов, даже если вы представляете их в представлении в отдельном состоянии. Я не знаю, какую конкретную технологию просмотра вы используете, но если это веб-приложение, вы можете, например, сохранить свои идентификаторы в скрытых полях ввода. Кроме того, я настоятельно рекомендую добавить 'orphanRemoval = true' в аннотацию' @ OneToMany' – crizzis

ответ

1

Вопрос: есть ли у кого-нибудь еще связь с TenderAddress?

Если ответ на ваш вопрос: да, вам нужно будет сделать итерационное обновление списка на основе какого-либо естественного ключа, а не идентификатора базы данных. Это связано с тем, что ваш входящий список может быть комбинацией новых и обновленных записей и должен быть объединен таким образом.

  • Iterate новый список
    • Для любого нового элемента списка, который не найден в старом списке, добавьте его в старый список.
    • Для любого нового элемента списка, который находится в старом списке, обновите его атрибуты.
  • Iterate старый список
    • Для любого старого элемента списка, который не найден в новом списке, удалите его.

Если ответ на ваш вопрос не, то вы могли бы переработать аннотации отображения и выполнить то, что вы думали, что будет работать. Вместо того, чтобы рассматривать TenderAddress как тип объекта, позволяет изменять его следует рассматривать как @Embeddable и поместить ее в @ElementCollection, как показано ниже:

@Entity 
public class Tender { 
    @ElementCollection 
    private Set<TenderAddress> addresses; 
} 

@Embeddable 
public class TenderAddress { 
} 

В этом случае, вы можете теперь спокойно заменить всю коллекцию TenderAddress и Hibernate будет в основном выполнять массовое удаление из таблицы коллекций на основе первичного ключа Tender, а затем повторно вставляет все новые строки из нового списка, который будет работать с кодом, который вы представили в своем вопросе.

+0

спасибо за ответ. Ответ на ваш вопрос НЕТ. Он не имеет каких-либо ассоциаций с любыми другими объектами. Однако, вместо того, чтобы идти так, как вы упомянули с помощью '@ Embeddable', каким будет альтернативный способ преодоления моей проблемы, сохраняя сущность' TenderAddress' как есть? Это первый способ, который вы предложили? – vigamage

+0

Да, если вы хотите сохранить его как '@ Entity', вам придется управлять слиянием двух списков самостоятельно. – Naros

 Смежные вопросы

  • Нет связанных вопросов^_^