在JPA中以多对多关系防止连接表中的重复条目

时间:2014-04-28 11:34:30

标签: hibernate jpa many-to-many eclipselink jpa-2.1

我正在使用EclipseLink 2.5.1(和Hibernate 4.3.5 final)。给出MySQL中的以下表格。

  • 产品
  • prod_colour(加入表格)
  • 颜色

产品与颜色之间存在多对多的关系。

产品可以有许多颜色,颜色可以与许多产品相关联。这种关系在数据库中由这些表表示。

prod_colour表分别来自其相关父表prod_idcolour_id的两个参考列productcolour

很明显,实体类Product有一个颜色列表 - java.util.List<Colour>,名为colourList

实体类Colour有一个产品列表 - java.util.List<Product>,名为productList


Colour实体中的关系:

public class Colour implements Serializable {

    @JoinTable(name = "prod_colour", joinColumns = {
        @JoinColumn(name = "colour_id", referencedColumnName = "prod_id")}, inverseJoinColumns = {
        @JoinColumn(name = "prod_id", referencedColumnName = "colour_id")})
    @ManyToMany(mappedBy = "colourList", fetch = FetchType.LAZY)
    private List<Product> productList; //Getter and setter.

    //---Utility methods---

    //Add rows to the prod_colour table.
    public void addToProduct(Product product) {
        this.getProductList().add(product);
        product.getColourList().add(this);
    }

    //Delete rows from the prod_colour table.
    public void removeFromProduct(Product product) {
        this.getProductList().remove(product);
        product.getColourList().remove(this);
    }
}

Product实体中的关系:

public class Product implements Serializable {

    @JoinTable(name = "prod_colour", joinColumns = {
        @JoinColumn(name = "prod_id", referencedColumnName = "prod_id")}, inverseJoinColumns = {
        @JoinColumn(name = "colour_id", referencedColumnName = "colour_id")})
    @ManyToMany(fetch = FetchType.LAZY)
    private List<Colour> colourList; //Getter and setter.
}

从关联的EJB中,插入操作执行如下。

@Override
@SuppressWarnings("unchecked")
public boolean insert(List<Colour> colours, Product product)
{
    int i=0;
    Long prodId=product.getProdId();
    for(Colour colour:colours)
    {
        Product p = entityManager.getReference(Product.class, prodId);
        colour.addToProduct(p);

        if(++i%49==0)
        {
            entityManager.flush();
        }
        entityManager.merge(colour);
        entityManager.merge(p);
    }
    return true;
}

一切正常。


当尝试重复行(与同一Colour实体关联的相同Product个实体)时,它们也会插入到我期望不应发生的prod_colour表中。

我是否需要执行一些额外的条件检查以避免重复插入或EclipseLink / Hibernate有一些机制来防止在这种情况下出现重复?

2 个答案:

答案 0 :(得分:7)

这对我来说也很令人惊讶。我一直以为它在连接表中将引用列作为复合主键,但它没有。如果您想拥有唯一记录,请尝试使用Set而不是List,或使用复合主键(color_id,product_id)创建自己的ManyToMany关系表。我没有更好的主意。

答案 1 :(得分:0)

您可以在JoinTable上指定一个uniqueConstraints,如下所示:

@JoinTable(name = "prod_colour", joinColumns = {
        @JoinColumn(name = "prod_id", referencedColumnName = "prod_id")}, inverseJoinColumns = {
        @JoinColumn(name = "colour_id", referencedColumnName = "colour_id")}, uniqueConstraints = @UniqueConstraint(columnNames = {
                            "colour_id", "prod_id" }))

当直接针对表并通过您的应用程序代码直接执行直接sql时,这将防止条目重复。