0

当我放入时inverse=trueset没有任何内容被删除。当我不这样做时,我从 中删除MealIngredientset然后 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>

是的,和之间的关系Meal与连接表Ingredient多对多的MealIngredient(是的,我也必须映射MealIngredient,因为该表中有额外的列)。

这个问题对我没有帮助,这个也没有。

编辑:仅插入适用于当前映射,更新仅在MealIngredient表中生成另一行。


编辑2: hashCodeequals实现:

MealIngredient$Id:(使用 Apache commons-lang EqualsBuilderHashCodeBuilder

@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();
}

膳食成分

@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();
}

我检查了日志,虽然我不知道 Hibernate 在幕后做了什么,但它确实使insertinto 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

当我从中删除MealIngredientMeal.ingredientsSet,Hibernate 会创建update并尝试设置mealIdnull

Hibernate: 
    update
        MealIngredients 
    set
        quantity=? 
    where
        ingredientId=? 
        and mealId=?
15:48:57,529 TRACE IntegerType:126 - binding null to parameter: 1
15:48:57,529 TRACE IntegerType:133 - binding '1' to parameter: 2
15:48:57,531 TRACE IntegerType:133 - binding '1' to parameter: 3
15:48:57,535  WARN JDBCExceptionReporter:77 - SQL Error: 0, SQLState: null
15:48:57,535 ERROR JDBCExceptionReporter:78 - [SQLITE_CONSTRAINT]  Abort due to constraint violation (MealIngredients.quantity may not be NULL)
4

2 回答 2

0

不幸的是,Hibernate 似乎不适用于复合主键。我必须将额外的 ID 列添加到多对多连接表(如 my MealIngredient)中并使用它。

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

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

<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>
于 2013-04-30T21:44:09.620 回答
0

我相信您正在寻找的解释就在这里。嗯,有点。不要看他的解释,这让我很困惑。他的例子非常好。

所以,无论如何,我认为您想要执行以下操作之一:

inverse=false并从您的配料集合中删除餐点成分,然后保存餐点

inverse=true并且必须清空 MealIngredient 中的餐实例变量并保存 MealIngredient

编辑:插入而不是更新的问题可能是由于您没有覆盖哈希码和等于。如果您使用的是 Eclipse,我相信它可以为您完成,但您必须告诉它在自动生成方法时使用复合键的两个属性。根据Hibernate 文档第 5 章

持久类必须重写 equals() 和 hashCode() 以实现复合标识符相等。它还必须实现 Serializable。

于 2013-04-26T23:12:28.777 回答