Radek Anuszewski
Radek Anuszewski

Reputation: 1910

Hibernate - automatic @ManyToMany update

I have Article entity, which has related Tags:

@Entity
@Table(name = "articles")
public class Article implements Serializable{
   //other things

   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
   private List<Tag> tags;
}

And Tag entity, which has related Articles:

@Entity
@Table(name = "tags")
public class Tag implements Serializable{
    //other things

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private List<Article> articles;
}

Is there any chance to configure Annotations in way, that if I save Article with specified Tag:

//simplified code
Tag tag = new Tag();
tags.add(tag)

article.setTags(tags);

articleService.save(article);

Articles related with Tag will be updated automatically, without axplicite call add method (tag.getArticles().add(article))? Or I have to do it manually?

This is part of unit test which shows what I try to achieve:

service.save(new TagDTO(null, tagValue, emptyArticles));
TagDTO tag = service.getAll().get(0);
List<TagDTO> tags = new ArrayList<>();
tags.add(tag);
articleService.save(new ArticleDTO(null, tags, articleContent));

List<ArticleDTO> articles = articleService.getAll();
assertEquals(1, articles.size());
final ArticleDTO articleWithTags = articles.get(0);
assertEquals(1, articleWithTags.getTags().size());
tags = service.getAll();
assertEquals(1, tags.size());
final TagDTO tagWithArticle = tags.get(0);
final List<ArticleDTO> articlesWithTag = tagWithArticle.getArticles();
assertEquals(1, articlesWithTag.size()); //it fails

Which is failing now, because Tag wasn't updated with related Article.

Thank you in advance for answers!

Upvotes: 0

Views: 127

Answers (1)

Guillermo
Guillermo

Reputation: 1533

You are missing mappedBy attribute on your many-to-many relationship. If you don't use it, then hibernate thinks that you have two differente unidirectional relationships. I mean your code represents this:

  • Article * ------------------[tags]-> * Tag
  • Tag * ------------------[articles]-> * Article

instead of this:

  • Article * <-[articles]------[tags]-> * Tag

Here is one way to make just one many-to-many bidirectional relationship between Article and Tag. Note the mappedBy attribute on Tag->articles collection.

@Entity
@Table(name = "articles")
public class Article implements Serializable{
   //other things

   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
   private List<Tag> tags;
}

@Entity
@Table(name = "tags")
public class Tag implements Serializable{
    //other things

    @ManyToMany(mappedBy="tags" ,cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private List<Article> articles;
}

Edit: Take a look at this Hibernate Documentation to see how to code differente bidirectional associations scenarios.

Upvotes: 2

Related Questions