我有一个带有基类的继承层次结构:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
abstract Instrument {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@OneToMany(mappedBy = "instrument1", fetch = FetchType.LAZY)
List<Market> markets;
abstract Type getType(); // Type is an Enum containing Currency & Commodity
}
还有两个子类
Commodity
和 Currency
例如
@Entity
@DiscriminatorValue("CUR")
@PrimaryKeyJoinColumn(name = "INS_ID"))
public class Currency extends Instrument {
...
getType() {
returns Type.Currency;
}
}
每种工具都可以在多个市场上市:
@Entity
public class Market {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "INS_ID")
private Instrument instrument1; // Currency or Commodity listed on the market
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "CUR_ID")
private Currency instrument2; // Base currency of the market
}
我创建了一个
CRUDRepository
方法来选择所有市场及其工具和基础货币:
@Query("SELECT m FROM Market m LEFT JOIN FETCH m.instrument1 LEFT JOIN FETCH m.instrument2")
public List<Market> findAllMarkets();
但是由于某种原因,当我尝试做类似的事情时:
findAllMarkets()
.stream()
.filter(m -> m.getInstrument1().getType() == Type.Currency)
.map(m -> (Currency) m.getInstrument1())
.collect(toList());
我得到一个
ClassCastException
,因为 Instrument1
实际上是 Instrument
的代理类型,而不是我期望的 Currency
。这似乎是间歇性发生的,有些是实际的 Currency
实例,有些是 instrument_$$_jvst965_19
代理。
有没有办法可以强制 Hibernate 不使用代理来执行此查询?
我怀疑这与 Hibernate Session 或 L2 Cache 有关。
在我的应用程序的其他地方,我正在查询仪器上没有
Left Join Fetch
的实体,例如喜欢:
SELECT m FROM Market m
我注意到,如果我将此调用更改为也包含
Left Join Fetch
,那么我的问题就得到了解决。或者在方法调用之前调用 findAllMarkets
而不使用 Left Join Fetch
也可以解决问题。
要阻止这种情况发生,您可以将
@Proxy(lazy=false)
添加到您的基类中,例如
@Proxy(lazy=false)
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
abstract Instrument {
...
}
但是,如果您调用
SELECT m FROM Market m
,这将导致 Hibernates n+1 方法,因为它将选择所有市场,然后在单独的查询中加载每个工具。
如果您获得代理,则意味着您的市场实体之一已经在持久性单元中。如果您不需要代理,请确保在查询数据库之前没有管理任何市场实体。