2

我在阻止将重复值插入 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 个整体插入到数据库中,但由于上述情况,我不能仅按名称施加限制。

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

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

任何帮助将不胜感激,谢谢!

4

1 回答 1

1

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

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

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

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

@org.hibernate.annotations.Check
于 2013-10-15T13:39:53.137 回答