当我将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>
是的,Meal
与Ingredient
之间的关系是多对多与联接表MealIngredient
(是的,我必须映射{{ 1}},因为该表中的其他列。)
编辑:
只插入与当前映射一起工作,更新只在MealIngredient
表中生成另一行。
修改2: MealIngredient
和hashCode
实施:
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
答案 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
,级联删除也有效!)。
我为实体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>