簡體   English   中英

在具有額外列關聯的多對多中使用 cascade.all

[英]Using cascade.all in a many-to-many with extra columns association

搜索了很長時間后,我想知道我的代碼是否錯誤,或者在 Hibernate 中是否根本不可能。

我會用一個假的例子來解釋我的問題。 假設我的數據庫中有三個表,post、posttag 和 tag。 一個帖子可以有多個標簽,一個標簽可以用於我的多個帖子,所以這是一個多對多的關聯,但在(posttag)之間的表中還有額外的列。

示例實體關系圖

所以,在我的代碼中,我有 3 個實體和一個 class 作為 posttag 的復合鍵。

郵政實體:

@Entity
@Table(name = "post", catalog = "fakeExample")
public class PostEntity implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "IDPOST", nullable = false)
    private Integer idpost;
    
    @OneToMany(mappedBy = "post", targetEntity = PostTagEntity.class, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<PostTagEntity> listOfPostTag = new ArrayList<>();

    public void setIdpost(Integer idpost)
    {
        this.idpost = idpost;
    }

    public Integer getIdpost()
    {
        return this.idpost;
    }
    
    public void setListOfPostTag(List<PostTagEntity> listOfPostTag)
    {
        if (listOfPostTag != null)
        {
            this.listOfPostTag.clear();
            this.listOfPostTag.addAll(listOfPostTag);
        }
    }
    
    public List<PostTagEntity> getListOfPostTag()
    {
        return this.listOfPostTag;
    }
}

標簽實體:

@Entity
@Table(name = "tag", catalog = "fakeExample")
public class TagEntity implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "IDTAG", nullable = false)
    private Integer idtag;
    
    @OneToMany(mappedBy = "tag", targetEntity = PostTagEntity.class, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<PostTagEntity> listOfPostTag = new ArrayList<>();

    public void setIdtag(Integer idtag)
    {
        this.idtag = idtag;
    }

    public Integer getIdtag()
    {
        return this.idtag;
    }
    
    public void setListOfPostTag(List<PostTagEntity> listOfPostTag)
    {
        if (listOfPostTag != null)
        {
            this.listOfPostTag.clear();
            this.listOfPostTag.addAll(listOfPostTag);
        }
    }
    
    public List<PostTagEntity> getListOfPostTag()
    {
        return this.listOfPostTag;
    }
}

PostTagEntity:

@Entity
@Table(name = "posttag", catalog = "fakeExample")
public class PostTagEntity implements Serializable
{
    @EmbeddedId
    private PostTagEntityKey compositePrimaryKey = new PostTagEntityKey();
    
    @Column(name = "EXTRACOLUMN")
    private Integer extraColumn;
    
    @ManyToOne
    @JoinColumn(name = "IDPOST", referencedColumnName = "IDPOST", nullable = false)
    @MapsId("idpost")
    private PostEntity post;
    
    @ManyToOne
    @JoinColumn(name = "IDTAG", referencedColumnName = "IDTAG", nullable = false)
    @MapsId("idtag")
    private TagEntity tag;

    public void setIdpost(Integer idpost)
    {
        this.compositePrimaryKey.setIdpost(idpost);
    }
    
    public Integer getIdpost()
    {
        return this.compositePrimaryKey.getIdpost();
    }
    
    public void setIdtag(Integer idtag)
    {
        this.compositePrimaryKey.setIdtag(idtag);
    }
    
    public Integer getIdtag()
    {
        return this.compositePrimaryKey.getIdtag();
    }
    
    public void setExtraColumn(Integer extraColumn)
    {
        this.extraColumn = extraColumn;
    }
    
    public Integer getExtraColumn()
    {
        return this.extraColumn;
    }
    
    public void setPost(PostEntity post)
    {
        this.post = post;
    }
    
    public PostEntity getPost()
    {
        return this.post;
    }
    
    public void setTag(TagEntity tag)
    {
        this.tag= tag;
    }
    
    public TagEntity getTag()
    {
        return this.tag;
    }
}

PostTagEntityKey:

@Embeddable
public class PostTagEntityKey implements Serializable
{
    @Column(name = "IDPOST", nullable = false)
    private Integer idpost;
    @Column(name = "IDTAG", nullable = false)
    private Integer idtag;
    
    public PostTagEntityKey()
    {
    }
    
    public PostTagEntityKey(Integer idpost, Integer idtag)
    {
        this.idsalle = idsalle;
        this.idequipement = idequipement;
    }
    
    public void setIdpost(Integer value)
    {
        this.idpost = value;
    }
    
    public Integer getIdpost()
    {
        return this.idpost;
    }
    
    public void setIdtag(Integer value)
    {
        this.idtag = value;
    }
    
    public Integer getIdtag()
    {
        return this.idtag;
    }
    
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (obj == null)
        {
            return false;
        }
        if (this.getClass() != obj.getClass())
        {
            return false;
        }
        PostTagEntityKey other = (PostTagEntityKey) obj;
        if (this.idpost == null ? other.idpost != null : !this.idpost.equals((Object) other.idpost))
        {
            return false;
        }
        if (this.idpost == null ? other.idpost != null
                : !this.idtag.equals((Object) other.idtag))
        {
            return false;
        }
        return true;
    }
    
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        
        result = prime * result + ((idpost == null) ? 0 : idpost.hashCode());
        result = prime * result + ((idtag == null) ? 0 : idtag.hashCode());
        
        return result;
    }
}

另外,我使用的是 Spring,所以這里是我進行插入或其他操作時涉及的少數 class。 我不認為問題來自這里,但以防萬一。

郵政服務:

public interface PostService
{
    public List<PostEntity> findAll();
    
    public Optional<PostEntity> findById(int var1);
    
    public PostEntity save(PostEntity var1);
    
    public void deleteById(int var1);
}

PostImpl:

@Service
public class PostImpl implements PostService
{
    @Autowired
    private PostRepository repository;
    
    @Override
    public List<PostEntity> findAll()
    {
        return this.repository.findAll();
    }
    
    @Override
    public Optional<PostEntity> findById(int id)
    {
        return this.repository.findById(id);
    }
    
    @Override
    public PostEntity save(PostEntity toSave)
    {
        return (PostEntity) this.repository.save(toSave);
    }
    
    @Override
    public void deleteById(int id)
    {
        this.repository.deleteById(id);
    }
}

后存儲庫:

@Repository
public interface PostRepository extends JpaRepository<PostEntity, Integer>, JpaSpecificationExecutor<PostEntity>, PagingAndSortingRepository<PostEntity, Integer>
{
}

因此,當我需要插入帖子時,我只需使用以下內容:

@Autowired
PostService postService;
public PostEntity createPost(PostEntity post)
{
    return this.postService.save(post);
}

對我來說, Hibernate 的預期行為將是:

  • 當我插入帖子時,插入帖子並將每個 postTag 插入 listOfPostTag
  • 當我更新帖子時,刪除 listOfPostTag 中每個丟失的 postTag,在 listOfPostTag 中添加每個新 postTag,更新 listOfPostTag 中的更改 postTag 並更新帖子
  • 當我刪除帖子時,刪除 listOfPostTag 中的每個 postTag 並刪除帖子

但是,當我嘗試插入帖子時,出現錯誤。 從我所做的許多測試來看,似乎 Hibernate 成功插入帖子,然后嘗試插入 postTags,但失敗,因為 PostTagEntityKey 中的 idPost 仍然是 null。 我本來希望 Hibernate 使用插入帖子中的 id 更新它。

所以我的問題是 hibernate 可以在我描述的情況下做到這一點嗎? 還是我必須手動完成(不使用級聯模式進行插入/更新)? 解釋可能是復合鍵,雙向,其他東西是不可能的,或者這不是 hibernate 應該做的事情。 我想知道這是否可能,如果是,我做錯了什么?

如果這是不可能的,我想知道如果你甚至不能為像中間表這樣常見的東西做它,那么在級聯中插入東西有什么意義。

我沒有嘗試編寫這個假示例,但我相信它會產生相同的結果,因為我幾乎沒有改變原始示例。 我也跳過了創建 postEntity 的部分,因為在我的例子中它是從 JSON 解析的。 我使用了調試器並嘗試了不同的東西,所以我幾乎可以肯定問題不是來自這里。 每個字段都被填滿,即使是 PostTagEntityKey 中的 idTag。 只是 PostTagEntityKey 中的 idPost 是 null 因為帖子尚未插入。 並且 hibernate 在插入帖子后不會更新它。 我開始相信級聯模式無法更新它,也許就是這樣。

創建PostEntity時,應在 PostEntity 中使用此方法

private void addPostTag(PostTagEntity postTag){
    postTag.setPost(this);
    this.listOfPostTag.add(postTag);
}

我認為這將解決您的問題

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM