如何在JPA中对多级子进程执行所有级联操作(PERSIST,UPDATE,REMOVE)

use*_*506 5 jpa spring-boot

我有3个表(表1,表2,表3).表1通过使用主键的@onetomany与表2相关.表2由@manytoone与表3相关.表2中有EmbeddedId.

当我使用表1的主键获取详细信息时,我能够获取表2和表3中的数据.但是我无法保存和删除.保存和删除发生在表1的子表(即表2)上,但不影响表3(表2中的子项)

以下是所有三个表的实体模型

 @Entity
    @Table(name = "FEATUREMASTER")
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

    public class FeatureMaster implements Serializable {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        @Id 
        @Column(name = "FGID")
        private String featureid;

        @Column(name = "FEATURENAME", nullable = false, unique = false)
        private String featurename;

        @Column(name = "DESCRIPTION", nullable = true, unique = false)
        private String description;

        @Column(name = "LIBNAME", nullable = true, unique = false)
        private String libname;

        @Column(name = "ISENABLED", nullable = false, unique = false)
        private String isenabled;

        @Column(name = "EDRULEGRP", nullable = true, unique = false)
        private String edrulegrp;

        // Do Not use - [orphanRemoval = true & CascadeType.ALL]- If used, deletion is not happening 
        @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
        @JoinColumn(name = "FGID")
        private List<CfgMaster> parameters;

// Getters and Setters
}


    @Entity
    @Table(name = "CFGMASTER")
    public class CfgMaster implements Serializable {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;

        @EmbeddedId
        private CfgMasterPK id;

        @Column(name = "CONFIGNAME", length = 45, nullable = true, unique = false)
        private String parameter_name;

        @Column(name = "CONFIGTYPE", length = 20, nullable = true, unique = false)
        private String type;

        @Column(name = "SUBPARAM", nullable = true, unique = false)
        private Integer subparam;

        @Column(name = "CONFIGDESCRIPTION", nullable = true, unique = false)
        private String description;

        @Column(name = "CONFIGLIMITFROM", nullable = true, unique = false)
        private String from;

        @Column(name = "CONFIGLIMITTO", nullable = true, unique = false)
        private String to;

        @ManyToOne(cascade = {CascadeType.ALL}, optional = true, fetch = FetchType.LAZY )
    //  @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
        @NotFound(action=NotFoundAction.IGNORE) // This is required to handle when no CfgData is found
        @JoinColumns({
                @JoinColumn(name = "FGID", insertable = false, updatable = false),
                @JoinColumn(name = "DATAKEY", insertable = false, updatable = false) 
                })
        private CfgData cfgData;

//Getters and Setters
    }

@Entity
@Table(name = "CFGDATA")
public class CfgData implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;


    /*@EmbeddedId
    private CfgDataPK id;*/

    @Id
    @Column(name = "FGID")
    private String fgid;

    @Id
    @Column(name = "DATAKEY")
    private String datakey;

    @Column(name = "EPID", nullable = false, unique = false)
    private int epid;


    @Column(name = "RESERVED1", length = 45, nullable = true, unique = false)
    private String reserved1;

    @Column(name = "VALUE1", length = 100, nullable = true, unique = false)
    private String value1;

    @Column(name = "VALUE2", length = 100, nullable = true, unique = false)
    private String value2;
     //Getters and Setters
}
Run Code Online (Sandbox Code Playgroud)

我面临的问题是,我无法通过传递FeatureMaster的主要ID来删除/保存CfgData的实体.我做的任何操作只影响父母和孩子,而不是大孩子(CfgData)我尝试了很多谷歌搜索,但我找不到解决方案.

df7*_*899 3

(这里有一个假设,PK 是CfgMaster-FGID希望这是正确的。如果是这样......我想我可以解释发生了什么,尽管用当前的表映射来解决它是很棘手的)

看起来问题与insertable = false, updatable = false外键上是否存在有关。

如果同一实体上有两个属性映射到相同的列,则使用这些的通常原因。Hibernate 需要知道从哪个属性设置列值,因此最多有一个属性是可写的。

看起来这就是这里的问题,但有两次:


首先FeatureMasterparameters集合使用 的外键连接列FGID。因为这@OneToMany实际上是 上的一列CFGMASTER,(假定)已经由id属性映射,所以第二个映射需要是只读的。

FeatureMaster通过此更改,从到 的级联删除CfgMaster开始工作:

@OneToMany(cascade = { CascadeType.ALL }, orphanRemoval = true)
@JoinColumn(name = "FGID", insertable = false, updatable = false)
private List<CfgMaster> parameters = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)

其次CfgMaster,该cfgData属性使用只读@JoinColumns。我认为这样做的原因是(假设的)列重叠FGID

不幸的是,因为这些是 上的外键列CFGMASTER,这实际上CfgMaster.cfgData也使该属性变为只读。例如,切换到不重叠的可写列也可以在此处启用级联删除:

@ManyToOne(cascade = {
        CascadeType.ALL }, optional = true, fetch = FetchType.LAZY)
//  @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY)
@NotFound(action = NotFoundAction.IGNORE) // This is required to handle when no CfgData is found
@JoinColumns({
        @JoinColumn(name = "FGID2"),
        @JoinColumn(name = "DATAKEY") })
private CfgData cfgData;
Run Code Online (Sandbox Code Playgroud)

这甚至适用于孙子级联删除。

然而,显然这提出了下一个问题 - 有没有办法让 PKCfgData也成为两部分外键的一部分?我见过外键为主键的示例,但以前没有看到过额外的列。显然,您已经在这里管理了它,但副作用是该关系也是只读的,至少对于级联来说是这样。

虽然这不是您希望听到的,但从 Hibernate 的角度来看,这确实有一定道理。例如,如果@ManyToOne 属性为空,Hibernate 会希望将两列清空,这对于主键来说是一个问题。除非其他人更了解,否则我认为选择是更改数据库映射,或者如果这不是一个选项,则需要编写 的级联删除代码CfgData