JPA 2.0 многие-ко-многим с дополнительным столбцом - Обновить коллекцию - PullRequest
1 голос
/ 05 мая 2020

Я использую в следующем примере

@Entity
public class Employer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @OneToMany(mappedBy = "employer")
    private List<EmployerDeliveryAgent> deliveryAgentAssoc;

    // other properties and getters and setters
}

@Entity
public class DeliveryAgent {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @OneToMany(mappedBy = "deliveryAgent")
    private List<EmployerDeliveryAgent> employerAssoc;

    // other properties and getters and setters
}

Класс ассоциации

@Entity
@Table(name = "employer_delivery_agent")
@IdClass(EmployerDeliveryAgentId.class)
public class EmployerDeliveryAgent {

    @Id
    @ManyToOne
    @JoinColumn(name = "employer_id", referencedColumnName = "id")
    private Employer employer;

    @Id
    @ManyToOne
    @JoinColumn(name = "delivery_agent_id", referencedColumnName = "id")
    private DeliveryAgent deliveryAgent;

    @Column(name = "is_project_lead")
    private boolean isProjectLead;
}

Класс PK ассоциации:

public class EmployerDeliveryAgentId implements Serializable {

    private int employer;
    private int deliveryAgent;

    // getters/setters and most importantly equals() and hashCode()
}

Как сделать обновить List<EmployerDeliveryAgent> deliveryAgentAssoc;?

Если я получу сущность «Работодатель» и сделаю простой setDeliveryAgentAssoc(), установлю ее в новый список и сохраню сущность «Работодатель», я получу старый список и новый в моей БД .

Я также пробовал следующий код, но опять же он по какой-то причине не удаляет старую коллекцию:

employer.getDeliveryAgentAssoc().forEach(employerDeliveryAgentRepository::delete);
employer.setDeliveryAgent(newCollection);
employerRepository.save(employer);

Я хочу заменить все содержимое существующей коллекции новой коллекцией . Как мне это сделать?

Ответы [ 2 ]

2 голосов
/ 05 мая 2020

Вам не хватает концепции Owning сущности. Аннотация mappedBy в Employer и DeliveryAgent определяет объект-владелец отношения как объект EmployerDeliveryAgent. Поскольку вы сами определили все объекты и репозитории, вы также должны сами управлять ими.

Установка свойств отношения в сущности, не имеющей долга, не имеет никакого постоянства. В результате эти свойства предназначены только для запроса. Установка deliveryAgentAssoc или employerAssoc ничего не делает для JPA.

Кроме того, шаблон Embedded для ManyToMany новее и обычно работает лучше.

Наконец, используйте Set, если вы действительно не думаете, что у вас есть причина иметь упорядоченный List для отношений OneToMany. Наличие нескольких отношений List в сущности вызывает проблемы с JPA. Кроме того, не используйте примитивные типы Java в пакетах на основе JPA, поскольку это приведет к проблемам и путанице.

Распечатайте операторы SQL при написании кода, чтобы вы могли видеть, что происходит. Это важно, потому что JPA будет выполнять множество ленивых выборок, когда вы не смотрите, и если вы не понимаете, что происходит, и управляете ими, вы получаете ошибки и проблемы, которых вы не понимаете. Спросите любого кодировщика JPA о страшном LazyInitializationException.

Итак, в качестве предлагаемого результата:

@Entity
public class Employer {

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

    @OneToMany(mappedBy="employer")
    private Set<EmployerDeliveryAgent> deliveryAgentAssoc;

@Entity
public class DeliveryAgent {

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

    @OneToMany(mappedBy="deliveryAgent")
    private Set<EmployerDeliveryAgent> employerAssoc;

@Entity
@ToString
public class EmployerDeliveryAgent {

    @EmbeddedId
    private EmployerDeliveryAgentId id = new EmployerDeliveryAgentId();

    @ManyToOne
    @MapsId("employerId")
    private Employer employer;

    @ManyToOne
    @MapsId("deliveryAgentId")
    private DeliveryAgent deliveryAgent;

    @Column(name = "is_project_lead")
    private Boolean isProjectLead;

И ваш класс идентификатора:

@Embeddable
public class EmployerDeliveryAgentId implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long employerId;
    private Long deliveryAgentId;

И использовать это:

    Employer emp1 = new Employer();
    employerRepo.save(emp1);
    DeliveryAgent da1 = new DeliveryAgent();
    deliveryAgentRepo.save(da1);
    EmployerDeliveryAgent eda1 = new EmployerDeliveryAgent();
    eda1.setEmployer(emp1);
    eda1.setDeliveryAgent(da1);
    eda1.setProjectLead(false);
    employerDeliveryAgentRepo.save(eda1);
    DeliveryAgent da2 = new DeliveryAgent();
    deliveryAgentRepo.save(da2);
    EmployerDeliveryAgent eda2 = new EmployerDeliveryAgent();
    eda2.setEmployer(emp1);
    eda2.setDeliveryAgent(da2);
    eda2.setProjectLead(true);
    employerDeliveryAgentRepo.save(eda2);

    employerDeliveryAgentRepo.findAll().forEach(System.out::println);

    EmployerDeliveryAgent edaex = new EmployerDeliveryAgent();
    edaex.setEmployer(emp1);
    employerDeliveryAgentRepo.findAll(Example.of(edaex)).forEach(System.out::println);

    employerDeliveryAgentRepo.deleteAll( employerDeliveryAgentRepo.findAll(Example.of(edaex)));

, что приводит к следующим выводам журнала:

Hibernate: drop table delivery_agent if exists
Hibernate: drop table employer if exists
Hibernate: drop table employer_delivery_agent if exists
Hibernate: create table delivery_agent (id bigint generated by default as identity, primary key (id))
Hibernate: create table employer (id bigint generated by default as identity, primary key (id))
Hibernate: create table employer_delivery_agent (is_project_lead boolean, delivery_agent_id bigint not null, employer_id bigint not null, primary key (delivery_agent_id, employer_id))
Hibernate: alter table employer_delivery_agent add constraint FKqfdjch3412029revbsh103okx foreign key (delivery_agent_id) references delivery_agent
Hibernate: alter table employer_delivery_agent add constraint FKc3djdeycywdtbpn4muakrhhtq foreign key (employer_id) references employer
2020-05-05 10:56:36.200  INFO 7588 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-05-05 10:56:36.204  INFO 7588 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-05-05 10:56:36.403  INFO 7588 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.455 seconds (JVM running for 1.821)
Hibernate: insert into employer (id) values (null)
Hibernate: insert into delivery_agent (id) values (null)
Hibernate: select employerde0_.delivery_agent_id as delivery2_2_0_, employerde0_.employer_id as employer3_2_0_, employerde0_.is_project_lead as is_proje1_2_0_ from employer_delivery_agent employerde0_ where employerde0_.delivery_agent_id=? and employerde0_.employer_id=?
Hibernate: select deliveryag0_.id as id1_0_0_ from delivery_agent deliveryag0_ where deliveryag0_.id=?
Hibernate: select employer0_.id as id1_1_0_ from employer employer0_ where employer0_.id=?
Hibernate: insert into employer_delivery_agent (is_project_lead, delivery_agent_id, employer_id) values (?, ?, ?)
Hibernate: insert into delivery_agent (id) values (null)
Hibernate: select employerde0_.delivery_agent_id as delivery2_2_0_, employerde0_.employer_id as employer3_2_0_, employerde0_.is_project_lead as is_proje1_2_0_ from employer_delivery_agent employerde0_ where employerde0_.delivery_agent_id=? and employerde0_.employer_id=?
Hibernate: select deliveryag0_.id as id1_0_0_ from delivery_agent deliveryag0_ where deliveryag0_.id=?
Hibernate: select employer0_.id as id1_1_0_ from employer employer0_ where employer0_.id=?
Hibernate: insert into employer_delivery_agent (is_project_lead, delivery_agent_id, employer_id) values (?, ?, ?)
Hibernate: select employerde0_.delivery_agent_id as delivery2_2_, employerde0_.employer_id as employer3_2_, employerde0_.is_project_lead as is_proje1_2_ from employer_delivery_agent employerde0_
Hibernate: select deliveryag0_.id as id1_0_0_ from delivery_agent deliveryag0_ where deliveryag0_.id=?
Hibernate: select employer0_.id as id1_1_0_ from employer employer0_ where employer0_.id=?
Hibernate: select deliveryag0_.id as id1_0_0_ from delivery_agent deliveryag0_ where deliveryag0_.id=?
EmployerDeliveryAgent(id=com.example.demo.EmployerDeliveryAgentId@3e1, employer=com.example.demo.Employer@52ae997b, deliveryAgent=com.example.demo.DeliveryAgent@32f32623, isProjectLead=false)
EmployerDeliveryAgent(id=com.example.demo.EmployerDeliveryAgentId@400, employer=com.example.demo.Employer@52ae997b, deliveryAgent=com.example.demo.DeliveryAgent@7e15f4d4, isProjectLead=true)
Hibernate: select employerde0_.delivery_agent_id as delivery2_2_, employerde0_.employer_id as employer3_2_, employerde0_.is_project_lead as is_proje1_2_ from employer_delivery_agent employerde0_ inner join employer employer1_ on employerde0_.employer_id=employer1_.id where employer1_.id=1
Hibernate: select deliveryag0_.id as id1_0_0_ from delivery_agent deliveryag0_ where deliveryag0_.id=?
Hibernate: select employer0_.id as id1_1_0_ from employer employer0_ where employer0_.id=?
Hibernate: select deliveryag0_.id as id1_0_0_ from delivery_agent deliveryag0_ where deliveryag0_.id=?
EmployerDeliveryAgent(id=com.example.demo.EmployerDeliveryAgentId@3e1, employer=com.example.demo.Employer@62b57479, deliveryAgent=com.example.demo.DeliveryAgent@1903b5d, isProjectLead=false)
EmployerDeliveryAgent(id=com.example.demo.EmployerDeliveryAgentId@400, employer=com.example.demo.Employer@62b57479, deliveryAgent=com.example.demo.DeliveryAgent@5a90265a, isProjectLead=true)
Hibernate: select employerde0_.delivery_agent_id as delivery2_2_, employerde0_.employer_id as employer3_2_, employerde0_.is_project_lead as is_proje1_2_ from employer_delivery_agent employerde0_ inner join employer employer1_ on employerde0_.employer_id=employer1_.id where employer1_.id=1
Hibernate: select deliveryag0_.id as id1_0_0_ from delivery_agent deliveryag0_ where deliveryag0_.id=?
Hibernate: select employer0_.id as id1_1_0_ from employer employer0_ where employer0_.id=?
Hibernate: select deliveryag0_.id as id1_0_0_ from delivery_agent deliveryag0_ where deliveryag0_.id=?
Hibernate: select employerde0_.delivery_agent_id as delivery2_2_0_, employerde0_.employer_id as employer3_2_0_, employerde0_.is_project_lead as is_proje1_2_0_, deliveryag1_.id as id1_0_1_, employer2_.id as id1_1_2_ from employer_delivery_agent employerde0_ inner join delivery_agent deliveryag1_ on employerde0_.delivery_agent_id=deliveryag1_.id inner join employer employer2_ on employerde0_.employer_id=employer2_.id where employerde0_.delivery_agent_id=? and employerde0_.employer_id=?
Hibernate: select employerde0_.delivery_agent_id as delivery2_2_0_, employerde0_.employer_id as employer3_2_0_, employerde0_.is_project_lead as is_proje1_2_0_, deliveryag1_.id as id1_0_1_, employer2_.id as id1_1_2_ from employer_delivery_agent employerde0_ inner join delivery_agent deliveryag1_ on employerde0_.delivery_agent_id=deliveryag1_.id inner join employer employer2_ on employerde0_.employer_id=employer2_.id where employerde0_.delivery_agent_id=? and employerde0_.employer_id=?
Hibernate: delete from employer_delivery_agent where delivery_agent_id=? and employer_id=?
Hibernate: delete from employer_delivery_agent where delivery_agent_id=? and employer_id=?
0 голосов
/ 05 мая 2020

За обновление коллекции EmployerDeliveryAgent должны нести ответственность работодатель или агент доставки.

Добавьте следующие методы в класс Employer.

public void addEmployerAssoc(EmployerDeliveryAgent item) {
    item.setEmployer(this);
    deliveryAgentAssoc.add(item);
}

public void removeEmployerAssoc(EmployerDeliveryAgent item) {
    item.setEmployer(null);
    deliveryAgentAssoc.remove(item); // must implement equals/hashcode
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...