【问题标题】:PostgreSQL constraint violation error on ManyToMany relationship but foreign key should be present [duplicate]多对多关系上的PostgreSQL约束冲突错误,但应存在外键[重复]
【发布时间】:2020-02-26 08:24:48
【问题描述】:

我正在尝试建立一个与此处显示的系统非常相似的系统:

https://vladmihalcea.com/the-best-way-to-use-the-manytomany-annotation-with-jpa-and-hibernate/

PostgreSQL 模式的设置方式与下面显示的内容类相同,映射到具有 content_id 和 tag_id 的表中的标记类,它们在各自的表上有外键约束。我遇到的问题是,当尝试持久化一个新的内容对象时,我正在检查对象的标签是否存在,如果存在,我将使用 addTag 方法添加它们,然后持久化该对象。否则我创建它们并持久化对象。执行此操作的 POST 方法也如下所示。存储库成功找到了标签,因为它们已经被持久化,但是当我尝试持久化内容时出现以下错误: org.postgresql.util.PSQLException:错误:在表上插入或更新

"content_tag" violates foreign key constraint "tag_id_fkey"
  Detail: Key (tag_id)=(11) is not present in table "tag".

我单步执行了代码,当使用 addTag 方法将标签添加到内容中时,它显示它们的 id 与数据库中已有的标签匹配,所以我不明白为什么当我持久化内容时它是一个不同的身份证。有谁知道我可以如何防止这种情况发生并保持内容的持久性?

@Entity(name = "Content")
@Table(name = "content")
@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)
public class Content implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Type(type = "StringJsonObject")
    @Column(name = "text")
    private String text;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    @ManyToMany(cascade = {
            CascadeType.MERGE
    })
    @JoinTable(name = "content_tag",
            joinColumns = @JoinColumn(name = "tag_id"),
            inverseJoinColumns = @JoinColumn(name="content_id")
    )
    private Set<Tag> tags = new HashSet<>();

    public Set<Tag> getTags() {
        return tags;
    }

    public void setTags(Set<Tag> tags) {
        this.tags = tags;
    }

    public void addTag(Tag tag) {
        tags.add(tag);
        tag.getContents().add(this);
    }

    public void removeTag(Tag tag) {
        tags.remove(tag);
        tag.getContents().remove(this);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Content)) return false;
        return id != null && id.equals(((Content) o).getId());
    }

    @Override
    public int hashCode() {
        return 31;
    }
}

@Entity(name = "Tag")
@Table(name = "tag")
public class Tag implements Serializable {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "name")
    private String name;

    @ManyToMany(mappedBy = "tags")
    private Set<Content> contents = new HashSet<>();

    public Tag() {}

    public Tag(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Content> getContents() {
        return contents;
    }

    public void setContents(Set<Content> contents) {
        this.contents = contents;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Tag tag = (Tag) o;
        return Objects.equals(name, tag.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

@PostMapping(value = "/content", consumes = { MediaType.APPLICATION_JSON_VALUE },
        produces = { MediaType.APPLICATION_JSON_VALUE })
public ContentJSON createContent(@RequestBody(required = false) final String payload) {
    if (StringUtils.isEmpty(payload)) {
        throw new IllegalArgumentException(ServiceErrorCode.INVALID_REQUEST_BODY);
    }
    final ContentRequest request = convertPayloadToRequest(payload, ContentRequest.class);
    final Content content = new Content();
    content.setText(request.getContent().getText().toString());

    for (final String tag : request.getContent().getTags()) {
        final List<Tag> current = tagRepository.findByName(tag);
        if (current.isEmpty()) {
            final Tag newTag = new Tag(tag);
            tagRepository.save(newTag);
            content.addTag(newTag);
        } else {
            content.addTag(current.get(0));
        }

    }
    final Content response = contentRepository.save(content);

    Set<String> tagNames = new HashSet<>();
    for (final Tag tag : content.getTags()) {
        tagNames.add(tag.getName());
    }
    return new ContentJSON(response, tagNames);
}

【问题讨论】:

    标签: java spring postgresql hibernate jpa


    【解决方案1】:

    问题是下面的注释。

    @JoinTable(name = "content_tag",
            joinColumns = @JoinColumn(name = "content_id"),
            inverseJoinColumns = @JoinColumn(name="tag_id")
    )
    

    joinColumns 和 inverseJoinColumns 颠倒了

    【讨论】:

      猜你喜欢
      • 2013-03-12
      • 1970-01-01
      • 1970-01-01
      • 2021-07-22
      • 1970-01-01
      • 2015-08-19
      • 1970-01-01
      • 2017-12-31
      • 2019-06-20
      相关资源
      最近更新 更多