jpa 如何正确保存显式多对多关系

ki1q1bka  于 2022-11-14  发布在  其他
关注(0)|答案(2)|浏览(253)

我以前在JPA中建模了一个ManyToMany关系,但是现在我不得不将其设置为OneToMany和ManyToOne。我从一个朋友那里得到了一些输入,但是现在我无法正确地保存连接表。
这些是我的实体:
标签:

public class Label implements Serializable {

    @Id
    @GeneratedValue()
    @Column(updatable = false, nullable = false, columnDefinition = "BINARY(16)")
    private UUID id;

    // BEFORE
    // @OneToMany
    @OneToMany(mappedBy = "technology")
    private Set<TechnologyLabel> technology;

    //getters setters equal hashcode
}

工艺:

public class Technology implements Serializable {

    @Id
    @GeneratedValue
    @Column(updatable = false, nullable = false, columnDefinition = "BINARY(16)")
    private UUID uuid;

    @Column(nullable = false, length = 30)
    private String technologyName;

    // BEFORE
    // @OneToMany
    @OneToMany(mappedBy = "label")
    private Set<TechnologyLabel> labels;

    //getters setters equal hashcode
}

技术标签:

public class TechnologyLabel {

    @Id
    @EqualsAndHashCode.Include
    UUID technologyId;

    @Id
    @EqualsAndHashCode.Include
    @Column(name = "label__id")
    UUID labelId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(insertable = false, updatable = false)
    Technology technology;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(insertable = false, updatable = false)
    Label label;

    //getters setters equal hashcode

    @Data
    public static class PK implements Serializable {

        UUID technologyId;

        UUID labelId;
    }
}

我的问题是如何保存TechnologyLabel。我所做的是:
1.创建label并将其保存在DB中
1.创建technology并将其保存在DB中
1.创建technologyLabel,添加labeltechnology,并将其保存在DB中
步骤3一个例子是:

var technologyLabelList = new ArrayList<TechnologyLabel>();
    for (var t : technologies) {
        for (var l : labels) {
            var technologyLabel = new TechnologyLabel();
            technologyLabel.setTechnology(t);
            technologyLabel.setLabelId(l.getId());
            technologyLabel.setTechnologyId(t.getUuid());
            technologyLabel.setLabel(l);
            technologyLabelList.add(technologyLabel);
        }
    }
technologyLabelRepository.saveAll(technologyLabelList);

这样我的程序运行并创建了表。我遇到的问题是我必须手动设置labelIdtechnologyId。结果TechnologyLabel table看起来很奇怪,因为它有两次ID为空,一次为空。

我必须将labelId的列名设置为label__id,否则会出现以下错误:
异常错误:表[technology_label]包含由多个逻辑列名引用的物理列名[label_id]:[标签ID],[标签ID]

hjzp0vay

hjzp0vay1#

最简单的方法是多对多关系:

public class Technology {
    
    @Id
    @GeneratedValue
    @Column(updatable = false, nullable = false)
    private long uuid;
    
    @Column(nullable = false, length = 30)
    private String technologyName;
    
    @ManyToMany(cascade = CascadeType.ALL)
    private Set<Label> labels = new HashSet<>();
    
    public Set<Label> getLabels() {
         return labels;
    }

    public void setTechnologyName(String technologyName) {
        this.technologyName = technologyName;
    }

    public void add(Label label) {
         labels.add(label);
         label.getTechnologies().add(this);
     }
}

public class Label {
        @Id
        @GeneratedValue()
        @Column(updatable = false, nullable = false)
        private long id;
    
        @ManyToMany(cascade = CascadeType.ALL, mappedBy = "labels")
        private Set<Technology> technologies = new HashSet<>();
    
        public Set<Technology> getTechnologies() {
            return technologies;
        }
    
        public void add(Technology t) {
            technologies.add(t);
            t.getLabels().add(this);
        }
    }

关系在两侧定义,但需要Label类技术上的mappedBy,以确保它与Technology类中的关系方向相反。
这将自动创建一个额外的表来管理多对多关系。

4smxwvx5

4smxwvx52#

请尝试以下操作:

@Entity
  @IdClass(TechnologyLabelPk.class)
  public class TechnologyLabel {

    @Id
    UUID technologyId;

    @Id
    @Column(name = "label_id")//pick the column name you really want to use!
    UUID labelId;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("technologyId")//tells JPA to set your technologyId property from this relationship
    Technology technology;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("labelId")//tells JPA to set your labelId property from this relationship
    Label label;

  }

  public class TechnologyLabelPk implements Serializable {
     public UUID technologyId;
     public UUID labelId;
  }

这允许您直接使用ID属性,而无需提取关系(如果需要),或者在查询中使用ID属性而无需强制连接,但仍然让JPA只使用对象引用来管理所有内容。因此,您永远不需要自己设置TechnologyLabel.labelId或technologyId属性。这是一个通用模型,如果您正在创建Labels和Technology示例,您可以这样做而不必在创建它们之间的TechnologyLabel关系之前分配它们的PK。
缺点是您无法通过设置这些字段来创建对象-您必须设置TechnologyLabel.label和技术引用。

相关问题