首页 > 解决方案 > Spring Boot(JPA)中的多个@JoinTable

问题描述

我有以下代码(Spring Boot)可以完美运行:

@Getter
@Setter
@ManyToMany(fetch = FetchType.LAZY)
@Column(name = "fight")
@JoinTable(name = "fighter_fight",
        joinColumns = {@JoinColumn(name = "fighter_id")},
        inverseJoinColumns = {@JoinColumn(name = "fight_id")})
private Set<Fight> fights;

它正在创建这个表:

在此处输入图像描述

我需要有三列。让我们说两个fighter_id叫做 first_fighter_idandsecond_fighter_idfight_id。当我尝试再添加一行时

 joinColumns = {@JoinColumn(name = "fighter_id")},

我收到一个错误(“重复的属性 joinColumns”)。如何在一个表中有两列具有相同的对象(Fighter在我的情况下)?

标签: spring-bootjpaspring-data-jpa

解决方案


首先,您应该考虑您是否在描述正确的模式。如果您只有 fighter1 和 fighter2 那么您可能正在谈论两个ManyToOne这样的关系:

在此处输入图像描述

这应该很容易建模。如果您认为您实际上有ManyToMany关系,可能是 WWE 之类的,并且您希望关系中有一个附加属性,那么您需要一个具有属性的关系,如下所示:

在此处输入图像描述

这不是一个不常见的模式要求,并且通过与ManyToOne新实体的两个关系来实现,如下所示:

在此处输入图像描述

为此,简单的 JPA 实体需要像这样Embeddable使用实体EmbeddableId

@Entity
@Data
public class Fight {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}
@Entity
@Data
public class Fighter {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
}
@Entity
@Data
public class Fights {
    @EmbeddedId
    private FightsPK id;        
    @MapsId("fighterId")
    @ManyToOne
    private Fighter fighter;    
    @MapsId("fightId")
    @ManyToOne
    private Fight fight;        
    private String fId;
}
@Embeddable
@Data
public class FightsPK implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long fighterId;
    private Long fightId;
}

使用它会有点尴尬,但可行:

private void create() {
    Fighter f1 = new Fighter();
    fighterRepo.save(f1);
    Fighter f2 = new Fighter();
    fighterRepo.save(f2);

    Fight f = new Fight();
    fightRepo.save(f);

    Fights f1s = new Fights();
    f1s.setId(new FightsPK());
    f1s.setFighter(f1);
    f1s.setFight(f);
    f1s.setFId("f1");
    fightsRepo.save(f1s);

    Fights f2s = new Fights();
    f2s.setId(new FightsPK());
    f2s.setFighter(f2);
    f2s.setFight(f);
    f2s.setFId("f2");
    fightsRepo.save(f2s);
}

fId字段是一个字符串,因此您可以在其中放置任何内容,例如,如果战斗组织者需要在该字段中输入他们自己的名称。您可能需要重新考虑是否需要最初描述的关系。只有两个战斗机,您可以在Fightfighter1 和 fighter1 名称中添加额外的字段。


推荐阅读