2013-10-15 2 views
2

중복 된 값이 (최대 절전 모드를 사용하여) MySQL 데이터베이스에 삽입되는 것을 방지하는 데 문제가있다. 문제는 다음과 같습니다. 상위 카테고리가있는 카테고리가 있습니다. 이름이 같지만 부모가 다른 두 개의 카테고리가있을 수 있습니다 (카테고리 이름을 businessId로 사용할 수없는 이유). 카테고리에 상위 항목 (예 : 최상위 카테고리)이없는 경우 parentId의 값은 NULL입니다. 데이터베이스에 삽입 된 복제물을 얻으려면 다음 코드에서 내가 뭘 잘못하고 있는지 이해할 수 없습니다.Hibernate UniqueConstraint 가능한 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 개의 엔트리 만 데이터베이스에 삽입되지만 위에서 설명한 상황 때문에 이름으로 만 제한을 적용 할 수는 없습니다.

편집 :. 나는이 문제를 해결하기 위해보고 있었다 가능성 중 하나의 MySQL의 경우 IFNULL (parentId 할 수있는, 0) 그리고 그러한 가능성은 예를 들어 가능한 것 같다 CONSTRAINT 정의 함수 사용 (이었다 오라클 (this 포스트에 따르면)에서,하지만 MySQL의에서

편집 2 :.. 실제로 나는 비슷한 문제를 가진 MySQL bug tracker명에서 발견 한 내가 MySQL을 사용하고 있기 때문에, 나는있는 어떤 코드를 확인했습니다 테이블을 생성하는 동안 생성되었으며 버그 보고서에있는 것과 거의 동일합니다 (사실 bugtracker에 언급 된 일부 스탠드 아트에 대해서는 버그가 아닌 것으로 간주됩니다.) 어쨌든, 내 동료 MS SQL Server에서 동일한 코드를 실행하려고 시도했지만 실제로 이름 필드와 null parentId에 동일한 값을 가진 행을 삽입 할 수 없었습니다. 원하는 CONSTRAINT를 만들기 위해 (적어도 MySQL을 사용하는) 데이터베이스 레벨 가능성이없는 것처럼 보입니다. 이것은 실망 스럽습니다. 이 문제에 대한 가능한 해결 방법 중 하나가 어떤 도움이 apreciated됩니다

(내 코드에서 하나 개 추가 find 쿼리를 유지하기 위해 선호한다,에 달라 붙지 않는 한, magic numbers 사용)이기 때문에, 대답을 수락, 감사합니다!

답변

1

간단한 해결책은 parentId을 "자체"로 설정하는 것입니다.

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

따라서 두 개의 "최상위"범주를 가질 수 없습니다. parentId을 Null 허용하지 않습니다.

문제점이 제약 조건에서 검사되지 않는 null 값과 관련이 있다고 확신합니다. 당신은 최대 절전 모드 체크를 시도 할 수는 있지만, 확실히 비효율적 일 것이다.

@org.hibernate.annotations.Check 
+0

나는 그것이 NULL 값과 관련이 있다는 것을 알아 냈고 나는 그것을 "자기"로 만드는 데 사용해야합니다 .. 질문은 어떻게됩니까? 하나의 아이디어는 "더미"카테고리를 삽입하는 것입니다.하지만 그것은 꽤 못생긴 해결책이라고 생각합니다. – Serhiy

+0

hibernate가 자체 엔티티의 레퍼런스와 함께 새로운 엔티티의 영속성을 처리 할 수 ​​있는지 확신 할 수 없다. 만약 아니라면, 조인을 새로운 category_to_parent 관계형 테이블에 매핑하면된다. 범주 테이블에는 이름 (고유, null 허용 불가) 만 포함됩니다. – albertredneck

+0

글쎄, 지금은 내 코드에 체크를 추가 했으므로, 삽입하기 전에 존재하는지 확인해 보겠다.하지만 추가 쿼리가있다 : - | .. – Serhiy