Royce
Royce

Reputation: 1595

Delete a row only into the join table

Question

Is it possible to delete a row into a join table created by @ManyToMany annotation?

Context

With this schema :

When a tag is removed from public Set<Tag> tags (a list into ARTICLE class) corresponding rows into TAGS_ARTICLES is removed too, but not the tag into TAG table.

The only way is to create a SQL script or JPA/Hibernate allow us to do that with annotations?

Code

My current code is : article.getTags().remove(tag);

This line remove the tag from the list, but the change is not done in database.

Conclusion

I saw this post : How to delete a row in join table with JPA , but relative tag must be deleted too (not my case).

Thanks.

Edit 1 : Expected result in database

Before delete

ARTICLE

| article_id |
| a1         |
| a2         |
| a3         |

TAGS_ARTICLES

| article_id | tag_id |
| a1         | t1     |
| a1         | t2     |
| a2         | t2     |

TAG

| article_id |
| t1         |
| t2         |

After delete t1 from a1 tag list

ARTICLE

| article_id |
| a1         |
| a2         |
| a3         |

TAGS_ARTICLES

| article_id | tag_id |
| a2         | t1     |
| a2         | t2     |

TAG

| article_id |
| t1         |
| t2         |

Edit 2 : Join table code

@Entity
public class Article {
     ...
     @ManyToMany
     @JoinTable(name = "tags_articles",
        joinColumns = @JoinColumn(name = "idarticle"),
        inverseJoinColumns = @JoinColumn(name = "idtag")
     )
     private Set<Tag> tags = new HashSet<>();
     ...
}

Upvotes: 1

Views: 1778

Answers (2)

LppEdd
LppEdd

Reputation: 21134

Edit: see comments

Using this set-up should produce the wanted result

class Article {
   ...  

   @ManyToMany
   @JoinTable(...)
   private Set<Tag> tags = new HashSet<>();
}

class Tag {
   ...

   @ManyToMany(mappedBy = "tags")
   private Set<Article> articles = new HashSet<>();
}

The Article entity is taking ownership of the relationship.


Old answer.

When a tag is removed from public Set<Tag> tags (a list into ARTICLE class) the corresponding row into TAGS_ARTICLES is removed too, but not the tag into TAG table.

By this I understand that the orphaned records are not deleted. And you want to delete them. Is this correct?

You might want to try using the Hibernate specific @Cascade annotation (documentation).
Just annotate your Collection<T> field.

@ManyToMany(...)
@Cascade(CascadeType.REMOVE) // or CascadeType.DELETE
private Set<Tag> tags = new HashSet<>();

Be sure to include it from the org.hibernate.annotations package.

Upvotes: 2

Sai prateek
Sai prateek

Reputation: 11896

The behavior of entity operation is depends on ownership of the relation, which is determined by where you place the mappedBy attribute to the annotation. Entity having mappedBy is the one which is not the owner. Both side of relationship cannot be owner.

Here you need to decide the correct owner. Let say the Tag is the owner. Then when deleting a Tag the relation TAGS_ARTICLES will be updated automatically. when deleting a TAGS_ARTICLES you have to take care of deleting the relation yourself.

@Entity
public class Tag{
    @ManyToMany
    Set<Tag_Articles> articles;
    //...
}

@Entity
public class Tag_Articles{
    @ManyToMany(mappedBy="articles")
    Set<Tag> tags;
    //...
}

For the entity relationship like above, you can try something like this -

entityManager.remove(articles)
for (Tag tag: articles.tags) {
     tag.articiles.remove(articles);
}

Upvotes: 2

Related Questions