views:

538

answers:

1

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=?
A: 

(Edited based on mappings / SQL queries / sample data posted in question / comments).

Your mapping specifies that FruitBowl contains a collection of Apples. 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:

  1. Banana is a subclass of Apple. In that case everything is correct, it should be returned as part of apples collection.
  2. 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 its entity_id (thus removing it from apples 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.

ChssPly76
The declaration is based on Apple rather than Fruit (just like you mentioned). But I do not see the FRUIT_TYPE = 'APPLE' in the select query.Edited the original post to include FruitBowl class.
kan
Can you post your query as well? In some cases, for example when you're loading a specific `FruitBowl` instance(s), its collection **cannot** contain anything other than `Apple`s by definition, so there's no reason to apply discriminator value condition.
ChssPly76
Updated original post with the generated SQL. The FRUIT table had the following records. The query should have picked up only the first record. But it picks up both. So I think the where clause fruit_type = 'A' is needed even while fetching records for the association. Kindly give your feedback.fruit_type entity_id pos colorA 1 1 whiteB 1 2 blue
kan