无法删除一对多关系中的子项

时间:2013-04-26 22:41:06

标签: java hibernate hibernate-mapping hibernate-onetomany

当我将inverse=true放入set时,不会删除任何内容。当我不这样做时,我从MealIngredient删除了set,然后Hibernate尝试设置null,它失败并抛出异常:

[SQLITE_CONSTRAINT]  Abort due to constraint violation (MealIngredients.mealId may not be NULL)

以下是XML映射:

<class name="restaurant.meal.Meal" table="Meals">
    <id name="id" type="integer">
        <column name="id" not-null="true" unique="true"/>
        <generator class="increment"/>
    </id>
    <!-- some other, simple properties -->

    <set name="ingredientsSet" cascade="all" lazy="false">
        <key>
            <column name="mealId" not-null="true" />
        </key>
        <one-to-many class="restaurant.meal.MealIngredient" />
    </set>
</class>

<class name="restaurant.meal.MealIngredient" table="MealIngredients">
    <composite-id name="id" class="restaurant.meal.MealIngredient$Id">
        <key-property name="ingredientId" />
        <key-property name="mealId" />
    </composite-id>
    <many-to-one name="ingredient" class="restaurant.storage.Ingredient" insert="false" update="false" lazy="false">
        <column name="ingredientId" not-null="true" />
    </many-to-one>
    <many-to-one name="meal" class="restaurant.meal.Meal" insert="false" update="false" lazy="false">
        <column name="mealId" not-null="true" />
    </many-to-one>
    <!-- other properties -->
</class>

是的,MealIngredient之间的关系是多对多与联接表MealIngredient(是的,我必须映射{{ 1}},因为该表中的其他列。)

question对我没有帮助,this也没有。

编辑: 只插入与当前映射一起工作,更新只在MealIngredient表中生成另一行。


修改2: MealIngredienthashCode实施:

MealIngredient $ Id :(使用Apache equals EqualsBuilder HashCodeBuilder

commons-lang

MealIngredient

@Override
public boolean equals(Object o) {
    if(!(o instanceof Id))
        return false;

    Id other = (Id) o;
    return new EqualsBuilder()
               .append(this.getMealId(), other.getMealId())
               .append(this.getIngredientId(), other.getIngredientId())
               .isEquals();
}

@Override
public int hashCode() {
    return new HashCodeBuilder()
               .append(this.getMealId())
               .append(this.getIngredientId())
               .hashCode();
}

我检查了日志,虽然我不知道Hibernate在幕后做了什么,但确实将@Override public boolean equals(Object o) { if(!(o instanceof MealIngredient)) return false; MealIngredient other = (MealIngredient) o; return this.getId().equals(other.getId()); } @Override public int hashCode() { return this.getId().hashCode(); } 变为insert

MealIngredient

当我从15:42:53,122 TRACE IntegerType:172 - returning '5' as column: quantity3_ Hibernate: insert into MealIngredients (quantity, ingredientId, mealId) values (?, ?, ?) 15:42:53,131 TRACE IntegerType:133 - binding '16' to parameter: 1 15:42:53,131 TRACE IntegerType:133 - binding '5' to parameter: 2 15:42:53,131 TRACE IntegerType:133 - binding '1' to parameter: 3 移除MealIngredient时,Hibernate会Meal.ingredientsSet并尝试将update设置为mealId

null

2 个答案:

答案 0 :(得分:0)

我相信您正在寻找的解释是here。好吧,有点。不要读他的解释,这让我很困惑。他的例子很棒。

所以,无论如何,我认为您想要做以下其中一项:

inverse=false并从你的食材中取出膳食成分    收集然后保存膳食

inverse=true并且必须在MealIngredient中取消用餐实例变量并保存MealIngredient

编辑 :插入而不是更新的问题可能是因为您没有过度使用哈希码和等号。如果你正在使用Eclipse,我相信它可以为你做,但你必须告诉它在自动生成方法时使用复合键的两个属性。每Hibernate documentation chapter 5

  

持久化类必须覆盖equals()和hashCode()   实现复合标识符相等。它还必须实施   序列化的。

答案 1 :(得分:0)

不幸的是,似乎Hibernate对复合主键不起作用。我不得不在多对多连接表中添加额外的ID列(比如我的MealIngredient)并使用它。

使用额外ID作为主键后,插入/更新/删除按预期工作(即使cascade设置为delete-orphan,级联删除也有效!)。

我为实体MealMealIngredient提供最终映射,以供将来参考。我希望当他们偶然发现连接表中其他属性/列的多对多关系时,这将有助于其他人。

<class name="restaurant.meal.Meal" table="Meals">
    <id name="id" type="integer">
        <column name="id" not-null="true" unique="true"/>
        <generator class="increment"/>
    </id>
    <!-- additional properties -->

    <set name="ingredientsSet" table="MealIngredients" cascade="all-delete-orphan" lazy="false" inverse="true">
        <key update="true">
            <column name="mealId" not-null="true" />
        </key>
        <one-to-many class="restaurant.meal.MealIngredient" />
    </set>
</class>
<class name="restaurant.meal.MealIngredient" table="MealIngredients">
    <id name="id" type="integer">
        <column name="id" not-null="true" unique="true"/>
        <generator class="increment"/>
    </id>
    <many-to-one name="ingredient" column="ingredientId" not-null="true" class="restaurant.storage.Ingredient"  lazy="false" />
    <many-to-one name="meal" column="mealId" not-null="true" class="restaurant.meal.Meal" lazy="false" />

    <!-- additional properties -->
</class>