java [Spring][JPA] ManyToMany时自动保存

ctehm74n  于 5个月前  发布在  Java
关注(0)|答案(1)|浏览(59)

我有两个Oracle表INDEXUSER,它们之间有关系表INDEX_USER(INDEX_ID NUMBER(8), USER_ID NUMBER(8), IN_CHARGE NUMBER(1), BACKUP NUMBER(1))
我在Java代码中这样表示INDEX表:

@Entity
@Data
public class Index {
//others attributs

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name="INDEX_USER", joinColumns = @JoinColumn(name="INDEX_ID"), joinColumns = @JoinColumn(name="USER_ID"))
@WhereJoinTable(clause = "IN_CHARGE = 1")
private Set<User> inCharges;

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name="INDEX_USER", joinColumns = @JoinColumn(name="INDEX_ID"), joinColumns = @JoinColumn(name="USER_ID"))
@WhereJoinTable(clause = "BACKUP = 1")
private Set<User> backups;

}

字符串
注意:B:INDEX_ID和USER_ID是关系表的主键
当我尝试用repository.save(index); spring保存一个新的Index时,我也尝试在关系表中保存我的Set,但我不想这样。
因为:

  • 它存储它们,而不带IN_CHARGE & PACKUP标志
  • 我可以有相同的用户负责和备份的索引,所以它的创建一个主键违规

我试着添加CascadeType.MERGE,但没有为我工作。
我不想使用@OneToMany关系并为我的关系表创建实体。我发现这样对我来说更清楚。

**编辑:**根据@kaqqao的提议,我修改了代码,使其具有@OneToMany关系:

public class IndexUser {

    @EmbeddedId
    private IndexUserPK id;

    @Basic
    @Column(name = "IN_CHARGE")
    private Boolean inCharge;

    @Basic
    @Column(name = "BACK_UP")
    private Boolean backUp;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "INDEX_ID", referencedColumnName = "ID", insertable = false, updatable = false)
    private Index index;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "USER_ID", referencedColumnName = "ID", insertable = false, updatable = false)
    private User user;

}


在我的Index类中添加一个新方法:

public void addUser(User user, boolean inCharge, boolean backup){
        IndexUserPK pk = new IndexUserPK(user.getId(), this.getId());
        IndexUser indexUser= new IndexUser(pk, inCharge, backup, this, user);
        this.getIndexUsers().add(indexUser);
    }


但是,当我尝试使用IndexUser对象列表保存新Index时,会出现此异常:

Caused by: oracle.jdbc.OracleDatabaseException: ORA-02291: violation de contrainte d'intégrité (SCHEMA.PK_INDEX_USER_FK) - clé parent introuvable


如果有人有任何关于如何解决这个问题的想法。谢谢

ve7v8dk2

ve7v8dk21#

如果关系表中的列不是外键(它是一个聚合),那么它应该被建模为一个实体本身。在您的情况下,这意味着引入一个实体,如:

@Entity
plublic class IndexUser {

    @EmbeddedId
    IndexUserId id;
 
    @ManyToOne
    @MapsId("indexId")
    Index index;
 
    @ManyToOne
    @MapsId("userId")
    User user;
 
    @Column
    boolean backup;
 
    @Column(name = "in_charge")
    boolean inCharge;

    ...
}

@Embeddable
public class IndexUserId
    implements Serializable {
 
    @Column(name = "index_id")
    Long indexId;
 
    @Column(name = "user_id")
    Long userId;

    ...

}

字符串
然后从UserIndex实体到IndexUser具有@OneToMany关系。

@Entity
public class Index {
 
    ...
 
    @OneToMany(mappedBy = "index")
    @WhereJoinTable(clause = "...")
    Set<IndexUser> backups;
     
    ...
}


查看此帖子以获取更多信息:https://vladmihalcea.com/the-best-way-to-map-a-many-to-many-association-with-extra-columns-when-using-jpa-and-hibernate/
或者this one,如果你觉得弗拉德的经典文章有点多的话。
但是,如果你最终发现所有的JPA(和ORM)有点多,看看这个:https://blog.jooq.org/the-second-best-way-to-fetch-a-spring-data-jpa-dto-projection/。我希望你能像我一样大开眼界。

相关问题