2014-03-06 50 views
0

我试图保存与我的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

我假设'标签的名称是唯一的.'意味着在包含文章和标签的表中,标签列被标记为唯一,这实际上意味着如果您尝试插入带有标签的其他文章另一篇文章已经有了会抛出你的异常。解决这个问题的方法是将标签存储在独立的表中,并且只通过外键插入对文章表中不同标签的引用。 ** TL; DR ** *不在'文章'中包含'标签',insead包含可以映射到'标签*的引用* –

+0

正是我正在这样做。我有第三列'article_tag',它包含文章和标签的'Id'。每篇文章和标签都存储在自己的表格中。 – hofmeister

+0

尝试将“HashSet”对象改为包含代表“标记”ID的“long”。之后,当您需要检查“Article”的标签时,您可以检索存储在“Article”记录中的“long”,然后查找“标签”表以将标签与从“Article”记录中获取的ID相匹配。 –

回答

1

一般文章和标签之间的关系是一个许多一对多关系,文章可能有许多标签每这些标签可以在许多文章中重复使用。

要表示许多一对多关系需要@ManyToMany注解。

也作出明确的东西,在OP则表示一个unidirectionaly@JoinTable注释已经在许多方面使用的一个一对多关系。这是创建连接表的原因。此外,如果在Tag类中使用注释,则将是另一个单向关系。 只要小心一点,因为它们将作为两个独立的单向关系进行处理,并且具有可能的奇怪行为,并且任何配置都不会影响这两个实体,因为它不是双面关系。

最后,如果需要有一个一个一对多单向关系,而且重复使用的标签,需要根据自己的名字来检索他们,使他们有正确的记录ID,然后设置为Article实例。如果您尝试设置Tag的新实例,该实例将没有记录标识但名称已存在,则jpa提供程序将尝试插入新标记,并且由于标记名称重复,将抛出唯一的约束异常。还需要删除article_tag表中涉及tag_id的任何唯一约束。

+0

是否适用于'@ ManyToMany'的唯一约束? – hofmeister

+0

@hofmeister如果您在提供的帖子中提及'Tag'表是的,那么标签名应该有唯一的约束。但是在关于'tag_id'的'join_table'' article_tag'中,在这两种情况下都不应该有一个唯一的约束,因为标签边是'many',无论是多对多还是单向一对多和标签ID将会多次关联,因此同一个ID可能出现在多个记录中。 – melc

+0

嗯。对不起,我仍然不知道,如何将具有唯一值的实体与其他实体连接起来。我用mappedBy尝试了@ManyToMany,但仍然得到了唯一的例外。 – hofmeister