我正在尝试保存与MySQL数据库中的文章相关的标签。这两列之间的关系是1:N。每个项目都有一个自动生成的密钥。标签的名称是唯一的。
如果我插入带有现有标记的新文章,我会得到唯一约束的重复条目异常(MySQLIntegrityConstraintViolationException)。这是我的两个实体:
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生成以下表格:文章,标记, article_tag 。对于第一篇文章,记录是正确的。
我使用以下代码插入新文章(仅用于测试):
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();
如何让JPA使用文章的现有标签,而不是创建新标签。如何正确设置这些组件之间的关系?
答案 0 :(得分:1)
通常,文章和标签之间的关系是多对多关系,因为文章可能包含多个标记,并且每个标记都可以在<中重复使用strong>很多文章。
要表明多对多关系, @ManyToMany 注释是必需的。
另外为了明确一点,在OP中它表示 unidirectionaly 一对多关系,因为 @JoinTable 注释具有在很多方面被使用过。这就是创建连接表的原因。另外,如果在Tag
类中使用 @ManyToOne 注释,多对一将是另一个单向关系。 请注意,因为它们将作为两个独立的单向关系处理,可能存在奇怪的行为,任何配置都不会影响两个实体,因为它不是一个双重关系。
最后,如果需要具有一对多单向关系但又重用标签,则需要根据其名称检索它们,以便它们具有正确的记录id然后设置为Article
实例。如果您尝试设置Tag
的新实例,该实例将没有记录ID但已存在的名称,则jpa提供程序将尝试插入新标记,并且将抛出唯一约束异常,因为重复的标签名称。还需要删除tag_id
表中article_tag
引用的任何唯一约束。