hibernate @DiscriminatorValue does not apply to associations
I have the following inheritance hierarchy.
@Entity
@Table(FRUIT)
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColum(name="FRUIT_TYPE",discriminatorType=STRING)
public class Fruit {
..
@Id
private FruitId id;
...
}
@DiscriminatorValue("APPLE")
public class Apple extends Fruit {
...
@ManyToOne
private FruitBowl bowl; //this association is only present in the subclass
...
}
class FruitBowl .. {
...
@OneToMany(fetch = FetchType.LAZY, mappedBy = "bowl")
@IndexColumn(name="POSITION",base = 1)
List<Apple> apples;
...
When I do a session.load(Apple.class,...)
, it adds FRUIT_TYPE = 'APPLE'
to the select query. But if I do a select on FruitBowl(which has a 1:m relationship with Apple), the select query on the Apple does not contain FRUIT_TYPE = 'APPLE'
. Why does this happen? How do I rectify the problem?
Query --Query for FruitBowl
select fruitbowl0_开发者_如何转开发.BOWL_ID as BOWL1_1_0_ from FRUITBOWL fruitbowl0_ where fruitbowl0_.BOWL_ID=?
--Query for Fruit to retrieve Apples (records with fruit_type ='A') --but it does not include that condition
select apples0_.ENTITY_ID as ENTITY3_1_, apples0_.POS as POS1_, apples0_.POS as POS0_0_, apples0_.ENTITY_ID as ENTITY3_0_0_, apples0_.COLOR as COLOR0_0_ from FRUIT apples0_ where apples0_.ENTITY_ID=?
You can add @DiscriminatorOptions(force=true)
to your "Fruit" class which will force hibernate to use the descriminator when querying this relationship.
This seems like something you would expect by default, but maybe there is some performance reason why it is not so.
(Edited based on mappings / SQL queries / sample data posted in question / comments).
Your mapping specifies that FruitBowl
contains a collection of Apple
s. Hibernate will therefore not add discriminator value condition to loader query for that collection because it knows in advance that only Apple
instances can be returned.
SQL queries you've posted do exactly that - load FruitBowl
by id and subsequently load apples
collection for that FruitBowl
instance. The problem lies with the data you've posted:
fruit_type entity_id pos color A 1 1 white B 1 2 blue
There's another instance of Fruit
with discriminator value B
- Banana
? :-) - that has the same entity_id
and thus is retrieved as part of collection loading query. The question here is - how was it inserted in the first place? There are two possible scenarios:
Banana
is a subclass ofApple
. In that case everything is correct, it should be returned as part ofapples
collection.- You've inserted the above data manually for testing purposes. This data is illegal from the Hibernate's standpoint - it would have NEVER be inserted by the Hibernate itself; this in turn leads to the behavior you're seeing. You need to either get rid of
Banana
row or remove itsentity_id
(thus removing it fromapples
collection).
Generally speaking, mixing object hierarchy and collection elements in the same table is not a good idea. Consider either re-mapping the hierarchy as "table-per-subclass" or mapping apples
collection using @JoinTable
- note that it will become uni-directional in the latter case.
精彩评论