deleteById()方法与ManyToMany映射不起作用:Spring Boot和JPA

huangapple go评论59阅读模式
英文:

deleteById() method not working with ManyToMany mapping: Spring Boot and JPA

问题

我有一个情景,在其中我在一个**Policy(保险政策)和一个County(县)实体表之间建立了ManyToMany(多对多)**映射。以下是实体代码-
InsurancePolicy.java-

@Entity
@Table(name = "insurance_policy")

public class InsurancePolicy {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="policy_id")
    private long policyId;

    @Column(name="policy_name",nullable = false,unique = true)
    private String policyName;

    //短描述
    @Column(name="policy_description",nullable = false)
    private String policyDescription;

    //长描述
    @Column(name="choose_description",nullable = false)
    private String chooseDescription;

    //多个政策可以属于一个公司
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", nullable = false)
    private Company company;

    //多个政策可以属于一个类别
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="category_id",nullable=false)
    private Category category;

    @ManyToMany(mappedBy = "queriedPolices",fetch = FetchType.LAZY,cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    private Set<User> usersQueried=new HashSet<>();

    @OneToMany(mappedBy = "policy", cascade = {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REMOVE},fetch = FetchType.LAZY)
    private Set<PolicyCounty> policyCounties = new HashSet<>();
}

PolicyCounty.java- (关联表)

@Data
@Entity
@Table(name="policy_county")
public class PolicyCounty {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="policy_county_id")
    private long policyStateId;

    @ManyToOne
    @JoinColumn(name="policy_id")
    private InsurancePolicy policy;

    @ManyToOne
    @JoinColumn(name = "county_id")
    private County county;

    @Column(name="cost",nullable = false)
    private double cost;
}

County.java-

@Entity
@Data
@Table(name="county")
public class County {
    @Id
    @Column(name="countyid")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long countyId;

    @Column(name="countyname",nullable = false,unique = true)
    private String countyName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "adminId", nullable = false)
    private Admin admin;

    @OneToMany(mappedBy = "county", cascade = {CascadeType.MERGE,CascadeType.PERSIST},fetch = FetchType.LAZY)
    private Set<PolicyCounty> policyStates = new HashSet<>();
}

问题-
我想要删除**InsurancePolicy(保险政策)**实体,并删除PolicyCounty表中对应的实体。为此,我编写了删除方法-

@Override
public long deletePolicy(long policyId) {
    boolean isPresent=insurancePolicyRepository.existsById(policyId);
    if(isPresent){
        insurancePolicyRepository.deleteById(policyId);
        return insurancePolicyRepository.count();
    }
    throw new ResourceNotFoundException("Policy with id "+policyId+" not found");
}

现在,当我尝试删除时,表中的实体不会被删除。在此操作期间,我没有收到任何异常。我怀疑问题可能出现在与实体一起使用的**Cascade Types(级联类型)**上。请帮我理解这个问题。

英文:

I have a scenario in which I have a ManyToMany mapping between a Policy and a County entity tables. Here is the entity code-
InsurancePolicy.java-

@Entity
@Table(name = &quot;insurance_policy&quot;)
public class InsurancePolicy {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name=&quot;policy_id&quot;)
private long policyId;
@Column(name=&quot;policy_name&quot;,nullable = false,unique = true)
private String policyName;
//Short description
@Column(name=&quot;policy_description&quot;,nullable = false)
private String policyDescription;
//Long description
@Column(name=&quot;choose_description&quot;,nullable = false)
private String chooseDescription;
//many policies can belong to one category
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = &quot;company_id&quot;, nullable = false)
private Company company;
//many policies can belong to one category
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name=&quot;category_id&quot;,nullable=false)
private Category category;
@ManyToMany(mappedBy = &quot;queriedPolices&quot;,fetch = FetchType.LAZY,cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
private Set&lt;User&gt; usersQueried=new HashSet&lt;&gt;();
@OneToMany(mappedBy = &quot;policy&quot;, cascade = {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REMOVE},fetch = FetchType.LAZY)
private Set&lt;PolicyCounty&gt; policyCounties = new HashSet&lt;&gt;();

PolicyCounty.java- (Relationship table)

@Data
@Entity
@Table(name=&quot;policy_county&quot;)
public class PolicyCounty {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name=&quot;policy_county_id&quot;)
private long policyStateId;
@ManyToOne
@JoinColumn(name=&quot;policy_id&quot;)
private InsurancePolicy policy;
@ManyToOne
@JoinColumn(name = &quot;county_id&quot;)
private County county;
@Column(name=&quot;cost&quot;,nullable = false)
private double cost;
}

County.java-

@Entity
@Data
@Table(name=&quot;county&quot;)
public class County {
@Id
@Column(name=&quot;countyid&quot;)
@GeneratedValue(strategy = GenerationType.AUTO)
private long countyId;
@Column(name=&quot;countyname&quot;,nullable = false,unique = true)
private String countyName;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = &quot;adminId&quot;, nullable = false)
private Admin admin;
@OneToMany(mappedBy = &quot;county&quot;, cascade = {CascadeType.MERGE,CascadeType.PERSIST},fetch = FetchType.LAZY)
private Set&lt;PolicyCounty&gt; policyStates = new HashSet&lt;&gt;();
}

Problem-
I want to delete the InsurancePolicy entity and also delete the corressponding entities in the PolicyCounty table. For it, I write the delete method-

@Override
public long deletePolicy(long policyId) {
boolean isPresent=insurancePolicyRepository.existsById(policyId);
if(isPresent){
insurancePolicyRepository.deleteById(policyId);
return insurancePolicyRepository.count();
}
throw new ResourceNotFoundException(&quot;Policy with id &quot;+policyId+&quot; not found&quot;);
}

Now, when I try to delete, the entities do not get deleted from the table. I am not getting any exception during this operation. I doubt that the problem is with the Cascade Types used with entities. Please help me understand this.

答案1

得分: 5

在你的代码中,你应该在InsurancePolicy类中有一个字段与County关联:

@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
@JoinTable(name = "policy_county",
        joinColumns = @JoinColumn(name = "insurance_policy_id"),
        inverseJoinColumns = @JoinColumn(name = "county_id"))
private Set<County> counties= new HashSet<>();

以及在County类中应该有一个字段如下:

@ManyToMany(mappedBy = "insurance_policy", fetch = FetchType.LAZY)
private Set<InsurancePolicy> students = new HashSet<>();

如果没有正确设置多对多关系,Hibernate将无法识别它。

但如果你的联接表中有额外的字段,例如成本字段,当你删除一个实体时,Hibernate将不会自动从联接表中删除相应的条目。相反,你需要使用本机SQL查询或Hibernate的Criteria API手动从联接表中删除条目。

另一个选项是将多对多关系转化为两个一对多关系,如下所示:

public class Student {
    // 省略其他字段和注解
    @OneToMany(mappedBy = "student", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Enrollment> enrollments = new HashSet<>();
}

public class Course {
    // 省略其他字段和注解
    @OneToMany(mappedBy = "course", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Enrollment> enrollments = new HashSet<>();
}

public class Enrollment {
    // 省略其他字段和注解
    @ManyToOne(fetch = FetchType.LAZY)
    private Student student;
    
    @ManyToOne(fetch = FetchType.LAZY)
    private Course course;
}

在上面的示例中,"Student"实体与"Enrollment"实体有一对多关系,"Course"实体也与"Enrollment"实体有一对多关系。两个关系都使用CascadeType.ALL选项设置了级联删除,这将在删除"Student"或"Course"实体时自动删除相关的"Enrollment"实体。orphanRemoval属性设置为true,将删除不再与"Student"或"Course"实体相关联的任何"Enrollment"实体。

有了级联删除设置,你可以删除"Student"或"Course"实体,所有相关的"Enrollment"实体将自动被删除。

英文:

in your code you should have an filed in InsurancePolicy that links to County

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
@JoinTable(name = &quot;policy_county&quot;,
joinColumns = @JoinColumn(name = &quot;insurance_policy_id&quot;),
inverseJoinColumns = @JoinColumn(name = &quot;county_id&quot;))
private Set&lt;County&gt; counties= new HashSet&lt;&gt;();

and you should have filed in county like this

 @ManyToMany(mappedBy = &quot;insurance_policy&quot;, fetch = FetchType.LAZY)
private Set&lt;InsurancePolicy &gt; students = new HashSet&lt;&gt;();

hibernate does not now you have many to many relation if you dont have it.

but If you have extra fields in your join table, such as a cost field, Hibernate will not automatically delete the corresponding entries from the join table when you delete a entity. Instead, you need to manually delete the entries from the join table using a native SQL query or Hibernate's Criteria API.

another option is convert many to many relation into 2 one to many relation like this :

public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = &quot;name&quot;)
private String name;
@OneToMany(mappedBy = &quot;student&quot;, cascade = CascadeType.ALL, orphanRemoval = true)
private Set&lt;Enrollment&gt; enrollments = new HashSet&lt;&gt;();}
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = &quot;name&quot;)
private String name;
@OneToMany(mappedBy = &quot;course&quot;, cascade = CascadeType.ALL, orphanRemoval = true)
private Set&lt;Enrollment&gt; enrollments = new HashSet&lt;&gt;();}
public class Enrollment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Student student;
@ManyToOne(fetch = FetchType.LAZY)
private Course course;
@Column(name = &quot;cost&quot;)
private BigDecimal cost;}

In the above example, the "Student" entity has a one-to-many relationship with the "Enrollment" entity, and the "Course" entity also has a one-to-many relationship with the "Enrollment" entity. Both relationships have cascading deletes set up using the CascadeType.ALL option, which will cause associated "Enrollment" entities to be deleted automatically when a "Student" or "Course" entity is deleted. The orphanRemoval attribute is set to true, which will remove any "Enrollment" entities that are no longer associated with a "Student" or "Course" entity.

With cascading deletes set up, you can delete a "Student" or "Course" entity and all associated "Enrollment" entities will be deleted automatically:

答案2

得分: 4

你首先必须决定所有者。在双向多对多关系中,您必须将一个实体设为所有者。在您的情况下,如果您想删除与InsurancePolicy实体相关的实体,则必须将InsurancePolicy实体设置为所有者。

要将所需的实体设置为所有者,您必须编写以下内容:

@ManyToMany(mappedBy = "entity name")

并且您必须设置 CascadeType.PERSIST

英文:

You have to decide the owner first. In bidirectional many to many relation, you have to set one entity as an owner. In your case if you want to delete corressponding entities of InsurancePolicy entity then you have to set InsurancePolicy entity as an owner.

You have to write this to set your required entity as an owner:

@ManyToMany(mappedBy = &quot;entity name&quot;)

And you have to set CascadeType.PERSIST.

huangapple
  • 本文由 发表于 2023年6月27日 19:53:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76564585.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定