Pergunta

I am trying to save tags which are related to an article in my MySQL database. The relation between those two columns is 1:N. Each item has an auto generated key. The name of a tag is unique.

If I insert a new article with an existing tag, I get a duplicate entry exception for the unique constraint (MySQLIntegrityConstraintViolationException). This are my two entities:

Article.java

@Entity
public class Article implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinTable
    private Set<Tag> tags = new HashSet<Tag>();

    /* getter and setter */
}

Tag.java

@Entity
public class Tag implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(unique = true)
    private String name;

    /* getter and setter */
}

Hibernate generate following tables: article, tag, article_tag. For the first article the records are correct.

I use following code to insert a new article (only for testing):

Article article = new Article();
Tag tag = new Tag();
/* set the values */
EntityManager em = EMF.getInstance().get();
em.getTransaction().begin();
em.merge(article);
em.getTransaction().commit();

How could I get JPA to use the existing tag for the article instead of create a new one. How do I set the relation between those so components correctly?

Foi útil?

Solução

In general the relationship between articles and tags is a many-to-many relationship as an article may have many tags and each of these tags may be reused in many articles.

To indicate a many-to-many relationship the @ManyToMany annotation is required.

Also to make something clear, in the OP it is indicated a unidirectionaly one-to-many relationship as the @JoinTable annotation has been used on the many side. This is the reason a join table has been created. In addition as a consequence if a @ManyToOne annotation is used in Tag class the many-to-one will be another unidirectional relationship. Just be careful there as they will be handled as two independent unidirectional relationship with probable strange behaviour and any configuration will not affect both entities, since it is not a biderictional relationship.

Finally, if it is required to have a one-to-many unidirectional relationship but also reuse the tags, it is required to retrieve them based on their name, so that they have the correct record id and then set the to the Article instance. If you try to set a new instance of Tag which will have no record id but a name that already exists, then the jpa provider will try to insert the new tag and a unique constraint exception will be thrown, because of the duplicate tag name. Also will need to remove any unique constraint referred to tag_id in article_tag table.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top