Hibernate UniqueConstraint具有可能的空值的多个列

时间:2013-10-15 12:00:42

标签: hibernate jpa unique-constraint

我遇到了阻止将重复值插入MySQL数据库(使用Hibernate)的问题。问题是:我有类别,它有父类别。可以有两个具有相同名称但具有不同父级的类别(这就是为什么类别名称不能用作businessId)。当类别没有父类(即顶级类别)时,parentId的值为NULL。我无法理解我在下面的代码中做错了什么来重复插入数据库。

这是我的实体类。

@Entity
@Table(name = "category", uniqueConstraints = {@UniqueConstraint(columnNames = {"name","parentId"})})
public class Category implements Serializable {
    @Id
    @Column(name="id")
    @GeneratedValue
    private long id;

    @Column(name="name")
    private String name;

    @ManyToOne(cascade={CascadeType.ALL})
    @JoinColumn(name="parentId", nullable=true)
    private Category parent;

    ...
}

以下是用于解析新类别的代码(我相信这里出了问题: - |)

 for (...) {
      Category parent = null;
      String [] categories = somePath.split("\\\\");

      for (String cat: categories) {
          Category category = new Category();
          category.setName(cat);
          category.setParent(parent);
          parent = categoryDB.insertCategory(category);
      }
 }

这是insertCategory函数

public Category insertCategory (Category category) {
    Session session = sessionFactory.openSession();
    Transaction transaction = null;
    try{
        transaction = session.beginTransaction();
        category.setId((Long) session.save(category)); 
        transaction.commit();
    } catch (HibernateException e) {
        if (transaction!=null) 
            transaction.rollback();
        ...
    } finally {
        session.close(); 
    }
    return category;
}

执行代码后,我在数据库中有以下条目:

select * from category;
+----+--------------+----------+
| id | name         | parentId |
+----+--------------+----------+
|  1 | A            |     NULL |
|  4 | A            |     NULL |
|  2 | B            |        1 |
|  3 | C            |        2 |
|  5 | B            |        4 |
|  6 | C            |        5 |
+----+--------------+----------+

当我尝试仅限制“名称”时,只有3个entires被插入数据库,但由于上述情况,我不能仅通过名称强加限制。

编辑:我看到解决这个问题的可能性之一是CONSTRAINT定义中的函数用法(在MySQL的情况下可能是IFNULL(parentId,0)。而且似乎这种可能性例如在Oracle中(根据this帖子),但不在MySQL中。

编辑2 :实际上我发现MySQL bug tracker有类似问题的人。由于我正在使用MySQL,我已经检查了在创建表时生成了什么代码,它几乎与Bug报告中的代码完全相同(实际上认为在bugtracker中提到的一些标准没有bug。无论如何,我的同事有试图在MS SQL Server上执行等效的代码,它实际上阻止了他在名字字段和null parentId上插入具有相同值的行。似乎没有数据库级别的可能性(至少使用MySQL)来制作所需的CONSTRAINT,这是相当的接受答案,因为这是该问题的可能解决方法之一(使用magic numbers,我不会坚持,更喜欢在我的代码中保留一个额外的find查询)

任何帮助都会被贬低, 谢谢!

1 个答案:

答案 0 :(得分:1)

一个简单的解决方案是让parentId成为“自我”。

+----+--------------+----------+
| id | name         | parentId |
+----+--------------+----------+
|  1 | A            |        1 |
|  2 | B            |        1 |
|  3 | C            |        2 |
|  4 | C            |        3 |
+----+--------------+----------+

所以你不可能永远不会有两个“顶级”类别。使parentId不可为空。

我确定您的问题与未在约束中检查的空值有关。你可以尝试使用hibernate检查,但它肯定会效率更低。

@org.hibernate.annotations.Check