正在将 Spring 应用程序从 Hibernate 4.3.1.Final 迁移到 5.4.27.Final

Migrating Spring application from Hibernate 4.3.1.Final to 5.4.27.Final

我正在尝试在旧的 Spring 应用程序中从休眠 4.3.1.Final 迁移到 5.4.27.Final(大多数 Spring 组件都在版本 4.3 上。13.Final).在更新版本修复几个小问题(class 导入)并使用 Maven 构建应用程序后,我在尝试在 Tomcat 7.0.107 上部署此 Web 应用程序时收到以下错误(部分堆栈跟踪指向到根例外):

2121 Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List hr.chus.plus.dao.repository.StatusUpdateRepository     .findAlarmLogsByZoneAndDatesAndNeedsAck(java.lang.Integer,java.lang.String,java.util.Date,java.util.Date)!
-- cut --
2150 Caused by: org.hibernate.QueryException: Could not resolve identifier `acks` as plural-attribute [FROM hr.chus.plus.dao.model.jpa.StatusUpdate WHERE updateType='ALARM'        AND relatedId=:alarmId   AND subtype='ZONE'   AND subtypeUuid=:zone   AND timestamp BETWEEN :start AND :end  AND needAck=true   AND size(acks)=0]
2151   at org.hibernate.QueryException.generateQueryException(QueryException.java:120) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2152   at org.hibernate.QueryException.wrapWithQueryString(QueryException.java:103) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2153   at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:220) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2154   at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:144) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2155   at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:113) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2156   at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:73) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2157   at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:162) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2158   at org.hibernate.internal.AbstractSharedSessionContract.getQueryPlan(AbstractSharedSessionContract.java:604) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2159   at org.hibernate.internal.AbstractSharedSessionContract.createQuery(AbstractSharedSessionContract.java:716) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]
2160   ... 79 common frames omitted
2161 Caused by: org.hibernate.QueryException: Could not resolve identifier `acks` as plural-attribute
2162   at org.hibernate.hql.internal.ast.tree.CollectionPathNode.from(CollectionPathNode.java:123) ~[hibernate-core-5.4.27.Final.jar:5.4.27.Final]

这个 JPQL 是 运行 并且可以很好地部署以前的版本。

上述实体的相关部分如下:

报警日志:

@Entity
@Table(name = "z_alarm_log")
@SecondaryTable(name = "z_alarm_log_data", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "id") })
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class AlarmLog extends AbstractLogEntity {

private static final int SUBTYPE_MAX_LENGTH = 10;

  @Column(name = "alarm_id")
  private Integer          alarmId;

  @Column(name = "trouble", columnDefinition = "TINYINT")
  private Boolean          trouble;

  @Lob
  @Basic(fetch = FetchType.EAGER)
  @Column(name = "data", columnDefinition = "BLOB", table = "z_alarm_log_data")
  private String           data;

  @Column(name = "need_ack", columnDefinition = "TINYINT")
  private Boolean          needAck            = false;

  @OneToMany(mappedBy = "log", fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
  private Set<AlarmLogAck> acks               = new HashSet<>();

  @Column(name = "code", nullable = false)
  private int              code               = 0;

  @Column(name = "subtype", length = SUBTYPE_MAX_LENGTH)
  private String           subtype;

  @Column(name = "subtype_id")
  private Integer          subtypeId;

  @Column(name = "subtype_uuid", nullable = true, columnDefinition = "CHAR")
  private String           subtypeUuid;

AlarmLogAck:

@Entity
@Table(name = "z_alarm_log_ack")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class AlarmLogAck extends AbstractLongIdEntity {
  private static final int MESSAGE_MAX_LENGTH = 200;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "zipato_id")
  private Zipato           zipato;

  @ManyToOne(fetch = FetchType.LAZY, optional = false)
  @JoinColumn(name = "log_id")
  private AlarmLog         log;

  @ManyToOne(fetch = FetchType.LAZY, optional = false)
  @JoinColumn(name = "user_id")
  private User             user;

  @Column(name = "show_date", nullable = false, columnDefinition = "DATETIME")
  private Date             showDate;

  @Column(name = "ack_date", nullable = true, columnDefinition = "DATETIME")
  private Date             ackDate;

  @Column(name = "message", length = MESSAGE_MAX_LENGTH, nullable = true)
  private String           message;

AlarmLogRepository:

  @Transactional(readOnly = true)
  public interface AlarmLogRepository extends JpaRepository<AlarmLog, Long>, JpaSpecificationExecutor<AlarmLog> {

    @Query("FROM AlarmLog " + //
        "WHERE zipato=:zipato " + //
        "  AND alarmId=:alarmId " + //
        "  AND subtype='ZONE' " + //
        "  AND subtypeUuid=:zone " + //
        "  AND timestamp BETWEEN :start AND :end" + //
        "  AND needAck=true " + //
        "  AND size(AlarmLog.acks)=0")
    List<AlarmLog> findAlarmLogsByZoneAndDatesAndNeedsAck(@Param("zipato") Zipato p_zipato,
                                                          @Param("alarmId") Integer p_alarmId,
                                                          @Param("zone") String p_zone,
                                                          @Param("start") Date p_start,
                                                          @Param("end") Date p_end);

我尝试用谷歌搜索这个错误,但找不到 plural-attribute 无法识别的确切组合。我还尝试调试到一定程度,发现此 Set 未被识别为 Collection 类型,或者更准确地说 acks Set 不在列表中,因此无法被识别为plural-attribute.

我不知道如何解决这个问题...

有什么想法吗?

对于该查询,您应该为实体设置标识符 AlarmLog 并按以下方式在 where 条件中使用该标识符:

...
@Query("FROM AlarmLog al " +
        "WHERE zipato=:zipato " +
        "  AND alarmId=:alarmId " +
        "  AND subtype='ZONE' " +
        "  AND subtypeUuid=:zone " + 
        "  AND timestamp BETWEEN :start AND :end" +
        "  AND needAck=true " + 
        "  AND size(al.acks)=0")
...