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
        )
    )