JPA 2.0多对多,带有额外的列-更新集合 [英] JPA 2.0 many-to-many with extra column - Update collection

查看:87
本文介绍了JPA 2.0多对多,带有额外的列-更新集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用以下示例

@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;?

如果我获得了Employer实体并执行了一个简单的setDeliveryAgentAssoc()并将其设置为新列表并保存了Employer实体,我最终将旧列表和新列表保存在数据库中.

If I get the Employer entity and do a simple setDeliveryAgentAssoc() and set it to a new list and save the Employer entity I end up with the old list and the new in my DB.

我也尝试了以下代码,但是由于某种原因,它也没有删除旧的集合:

I have also tried following code but again it does not remove the old collection for some reason:

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

我想用一个新集合替换现有集合的所有内容.我该怎么办?

I want to replace all the contents of the existing collection with a new collection. How do I do that?

推荐答案

您缺少Owning实体的概念. EmployerDeliveryAgent中的mappedBy注释将关系的拥有实体定义为EmployerDeliveryAgent实体.由于您已经定义了所有实体和存储库,因此您也必须自己管理它们.

You are missing the concept of Owning entity. The mappedBy annotation in Employer and DeliveryAgent defines the owning entity of the relationship as the EmployerDeliveryAgent entity. Since you have defined all the entities and repositories yourself you have to manage them yourself as well.

在非归因实体中设置关系属性不会产生任何持久性.结果,这些属性仅用于查询.设置deliveryAgentAssocemployerAssoc对于JPA无效.

Setting relationship properties in a non-owing entity doesn't do any persistence. As a result those properties are for query only. Setting deliveryAgentAssoc or employerAssoc doesn't do anything for JPA.

此外,ManyToManyEmbedded模式是较新的并且通常效果更好.

Also, the Embedded pattern of ManyToMany is newer and generally works better.

最后,除非您确实认为有理由为OneToMany关系订购有序的List,否则请使用Set.实体中具有多个List关系会导致JPA问题.另外,请勿在基于JPA的程序包中使用Java基本类型,因为这会导致问题和混乱.

Finally, use a Set unless you really think you have a reason to have an ordered List for OneToMany relations. Having multiple List relations in an entity causes JPA problems. Also, do not use Java primitive types in JPA based packages since that leads to problems and confusion.

在编写代码时打印出SQL语句,以便您了解发生了什么.这很重要,因为JPA会在您不查找时进行很多懒惰的访存,如果您不了解正在发生的情况并对其进行管理,则最终会遇到不了解的错误和问题.向任何JPA编码员询问有关可怕的LazyInitializationException.

Print out the SQL statements when writing your code so you can see what is going on. This is important because JPA will do lots of lazy fetches when you are not looking and if you don't understand that is happening and manage them you end up with errors and problems you don't understand. Ask any JPA coder about the dreaded LazyInitializationException.

因此,作为建议的结果:

So, as a suggested result:

@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;

您的ID类别:

@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)));

这将导致以下日志输出:

which results in the following Log outputs:

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=?

这篇关于JPA 2.0多对多,带有额外的列-更新集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆