Java Hibernate注释用于单个选择对象(带where),而不是用于多个集合
目前,我们有一个类,看起来像是去除了非个性化和非相关部分:Java Hibernate注释用于单个选择对象(带where),而不是用于多个集合,java,oracle,hibernate,max,hibernate-annotations,Java,Oracle,Hibernate,Max,Hibernate Annotations,目前,我们有一个类,看起来像是去除了非个性化和非相关部分: @Entity @Table(name = "MAIN_TABLE") public class MainTable extends AbstractTable { @OneToMany(fetch = FetchType.LAZY, mappedBy = "mainTable") @OrderBy("CREATED_ON DESC") private Set<MainTableState> states;
@Entity
@Table(name = "MAIN_TABLE")
public class MainTable extends AbstractTable {
@OneToMany(fetch = FetchType.LAZY, mappedBy = "mainTable")
@OrderBy("CREATED_ON DESC")
private Set<MainTableState> states;
...
public MainTableState getActiveState(){
if(this.states == null || this.states.isEmpty()){
return null;
}
MainTableState latest = states.iterator().next();
// The reason we use this for-loop, even though we have the @OrderBy annotation,
// Is because we can later add states to this list, which aren't automatically ordered
for(MainTableState state : states){
if(state.getCreatedOn() != null && latest.getCreatedOn() != null &&
state.getCreatedOn().after(latest.getCreatedOn()){
latest = state;
}
}
return latest;
}
...
}
那么,我的问题是,我应该把什么放在????要做到这一点?我假设我需要@Formula或类似的东西,但是我怎么能说hibernate应该返回MainTableState对象呢?我见过@Formula与MAX一起用于日期,但这是为了获取该日期属性,而不是基于该MAX日期获取整个对象
在@user2447161的建议之后,我使用了@Where注释,有时确实有助于将集合大小减少到1,但我还有两个相关问题:
如何使用@OnToMany和@Where but获取单个对象,而不是大小为1的对象列表?这可能吗?在过去的六年里,这个问题是否得到了解决
如何处理where子句中的随机别名?我可以这样做:
@OneToManyfetch=FetchType.LAZY,mappedBy=mainTable
@Whereclause=CREATED\u ON=从主表中选择MAXmts.CREATED\u ON,其中mts.FK\u MAIN\u ID=???.MAIN\u ID
私有集状态;//TODO获取单个对象而不是大小为1的集合
问题是???是hibernate生成的随机别名有时是this,有时是mainTable,等等。。如何将整个查询的别名设置为DB,以便在此处使用它?我还尝试了MAIN_TABLE.MAIN_ID,但它不起作用,如果没有别名,它也不起作用,因为它使用MainTableState别名而不是MainTable别名,如下所示
from
MAIN_TABLE this_
left outer join
MAIN_TABLE_STATUSES mainstat2_
on this_.main_id=mainstat2_.fk_main_id
and (
mainstat2_.created_on = (
SELECT
MAX(mts.created_on)
FROM
MAIN_TABLE_STATUSES mts
WHERE
-- mainstat2_.main_id should be this_.main_id instead here:
mts.fk_main_id = mainstat2_.main_id
)
)
好的,关于你的问题2,看起来你需要一个对现有代码影响最小的快速解决方案,这是可以接受的:你可以使用一个来处理别名并生成正确的sql语句。这样做: 在@Where子句中使用唯一字符串作为别名占位符,例如: …其中mts.FK_MAIN_ID=${MAIN_TABLE_ALIAS}.MAIN_ID 如果您的应用程序还没有,请创建一个扩展EmptyInterceptor的拦截器类,并将其配置为SessionFactory拦截器 重写onPrepareStatement方法,将占位符替换为“from MAIN_TABLE”之后的别名,如下所示: 公共字符串onPrepareStatementString sql{ 字符串modifiedSql=sql; 如果sql.包含${MAIN_TABLE_ALIAS}{ 字符串mainTableAlias=findMainTableAliassql; modifiedSql=sql。替换${MAIN\u TABLE\u ALIAS},mainTableAlias; } 返回修改后的dsql; } 请注意,hibernate在应用程序中生成的每个sql语句都将调用此方法 此外,您的@Where子句仅在使用联接时才能正常工作,因此您应该显式地设置获取模式 @fetchmode.JOIN
设置为states属性,以避免hibernate可能使用选择模式。除非在性能方面有大量的行、没有索引和/或非常严格的要求,否则我看不出这将是一个性能问题。在现代计算机中,for循环通常只需纳秒,加载一组而不是一行应该可以忽略不计。。另外,请确保在使用列表时立即获取列表,延迟加载可能会带来相当大的开销,可能比实际循环大很多。@Tobb我在问题中添加了另一行。for循环不是主要问题,而是java.lang.OutOfMemoryError:超过100万个MainTableState实例,超出了GC开销限制。这就是为什么我们只想保存一个活动状态,而不是当前未使用的整个集合的主要原因。或者从自定义查询中创建自己的DTO。。。
from
MAIN_TABLE this_
left outer join
MAIN_TABLE_STATUSES mainstat2_
on this_.main_id=mainstat2_.fk_main_id
and (
mainstat2_.created_on = (
SELECT
MAX(mts.created_on)
FROM
MAIN_TABLE_STATUSES mts
WHERE
-- mainstat2_.main_id should be this_.main_id instead here:
mts.fk_main_id = mainstat2_.main_id
)
)