When I put inverse=true
into set
, nothing gets deleted. When I don't, and I remove MealIngredient
from set
, then Hibernate tries to set null
, it fails and exception is thrown:
[SQLITE_CONSTRAINT] Abort due to constraint violation (MealIngredients.mealId may not be NULL)
Here are XML mappings:
<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>
Yes, the relationship between Meal
and Ingredient
is many-to-many with join table MealIngredient
(and yes, I have to map MealIngredient
as well, because of additional columns in that table).
This question did not help me, neither did this.
Edit:
Only inserting works with current mapping, update just generates another row in MealIngredient
table.
Edit 2: hashCode
and equals
implementations:
MealIngredient$Id: (uses Apache commons-lang
EqualsBuilder and HashCodeBuilder)
@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();
}
MealIngredient:
@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();
}
I checked log and although I don't know what Hibernate does under the hood, but it does make the insert
into 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
And when I remove MealIngredient
from Meal.ingredientsSet
, Hibernate makes update
and tries to set mealId
to null
:
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)