【问题标题】:hibernate @DiscriminatorValue does not apply to associationshibernate @DiscriminatorValue 不适用于关联
【发布时间】:2009-11-09 17:23:22
【问题描述】:

我有以下继承层次结构。

@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;
...

当我执行session.load(Apple.class,...) 时,它会将FRUIT_TYPE = 'APPLE' 添加到选择查询中。但是,如果我在 FruitBowl(与 Apple 的关系为 1:m)上进行选择,则 Apple 上的选择查询不包含 FRUIT_TYPE = 'APPLE'。为什么会这样?我该如何解决这个问题?

查询 --查询 FruitBowl

select fruitbowl0_.BOWL_ID as BOWL1_1_0_ from FRUITBOWL fruitbowl0_ where fruitbowl0_.BOWL_ID=? 

--查询 Fruit 以检索 Apples(fruit_type ='A' 的记录) --但它不包括那个条件

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

【问题讨论】:

  • @kan - 我已经根据您发布的查询/数据编辑了我的答案;请看一下。

标签: hibernate annotations associations hibernate-annotations


【解决方案1】:

您可以将@DiscriminatorOptions(force=true) 添加到您的“水果”类中,这将强制休眠在查询此关系时使用描述符。

这似乎是您在默认情况下所期望的,但也许有一些性能原因导致它不是这样。

【讨论】:

  • 因为一般来说判别器不是索引的一部分。因此,将其添加到 WHERE 子句确实会导致查询速度变慢。而且,考虑到他提供的数据,从 Hibernate 的角度来看,它并不是一个有效的映射。
【解决方案2】:

(根据映射/SQL 查询/问题中发布的示例数据/cmets 进行编辑)。

您的映射指定FruitBowl 包含Apples 的集合。因此,Hibernate 不会为该集合的加载器查询添加鉴别器值条件,因为它预先知道只能返回 Apple 实例。

您发布的 SQL 查询正是这样做的 - 按 id 加载 FruitBowl,然后为该 FruitBowl 实例加载 apples 集合。问题在于您发布的数据:

fruit_type entity_id pos 颜色 A 1 1 白色 B 1 2 蓝色

还有另一个Fruit 实例,其鉴别器值为B - Banana? :-) - 具有相同的entity_id,因此作为集合加载查询的一部分进行检索。这里的问题是 - 它是如何插入的?有两种可能的情况:

  1. BananaApple 的子类。在这种情况下,一切都是正确的,它应该作为apples 集合的一部分返回。
  2. 出于测试目的,您手动插入了上述数据。从 Hibernate 的角度来看,这些数据是非法的 - 它会 NEVER 由 Hibernate 本身插入;这反过来又会导致您看到的行为。您需要删除 Banana 行或删除其 entity_id(从而将其从 apples 集合中删除)。

一般来说,在同一个表中混合对象层次结构和集合元素并不是一个好主意。考虑将层次结构重新映射为“每个子类的表”或使用 @JoinTable 映射 apples 集合 - 请注意,在后一种情况下它将变成单向的。

【讨论】:

  • 声明是基于苹果而不是水果(就像你提到的那样)。但我在选择查询中没有看到 FRUIT_TYPE = 'APPLE'。编辑了原始帖子以包含 FruitBowl 类。
  • 您也可以发布您的查询吗?在某些情况下,例如当您加载特定的 FruitBowl 实例时,它的集合不能包含除 Apples 以外的任何内容,因此没有理由应用鉴别器值条件。
  • 使用生成的 SQL 更新了原始帖子。 FRUIT 表有以下记录。查询应该只拾取第一条记录。但它两者兼而有之。所以我认为即使在获取关联记录时也需要 where 子句 fruit_type = 'A'。请提供您的反馈。 fruit_type entity_id pos 颜色 A 1 1 白色 B 1 2 蓝色
猜你喜欢
  • 2012-06-30
  • 1970-01-01
  • 2013-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-09
  • 2018-01-18
相关资源
最近更新 更多