Hibernate Envers AuditQuery正在将_id添加到mapledBy列,并且由于异常“无法解析属性”而失败

时间:2018-09-16 10:42:15

标签: hibernate hibernate-envers

我正在使用Envers审核我的实体。但是,当我使用AuditQuery来获取我的实体及其关联实体的修订版时,它会失败,并带有以下异常:

could not resolve property: userid_id of: com.envers.domain.vo.UserOrgVO_AUD [select e__ from com.envers.domain.vo.UserOrgVO_AUD e__ where e__.userid_id = :userid_id and e__.originalId.REVISION_ID.id = (select max(e2__.originalId.REVISION_ID.id) from com.envers.domain.vo.UserOrgVO_AUD e2__ where e2__.originalId.REVISION_ID.id <= :revision and e__.originalId.id = e2__.originalId.id) and REVISION_TYPE != :delrevisiontype]

我的实体如下:

用户(id:长,名称:字符串,组织:Set [UserOrganisation])

UserOrganisation(id:Long,userid:Long,organisation:Organisation)

组织(id:长,名称:字符串)

VO类的定义如下

UserVO

@Entity(name = "USERS")
@Audited
public class UserVO {
  @Id
  @Column(name = "id")
  private Long id;

  @Column(nullable = false)
  private String name;

  @OneToMany (fetch = FetchType.EAGER, mappedBy = "userid", cascade = CascadeType.ALL, orphanRemoval = true)
  @Audited
  private List<UserOrgVO> organisations;

  /**............................................................

     constructors, getters and setters ....

     ............................................................*/
}

UserOrgVO

@Entity(name = "USER_ORGANISATIONS")
@Audited
public class UserOrgVO {
  @Id
  @Column(name = "ID")
  private Long id;

  @Column (name = "USER_ID")
  private Long userid;

  @ManyToOne
  @JoinColumn (name = "ORGANISATION_ID", nullable = false)
  private OrganisationVO organisation;

  @Column (name = "PREFERRED", nullable = false)
  private boolean preferred = false;

  /**............................................................

     constructors, getters and setters ....

     ............................................................*/
}

OrganisationVO

@Entity(name = "ORGANISATIONS")
@Audited
public class OrganisationVO {
  @Id
  private Long id;

  @Column(nullable = false, name = "NAME", length = 70)
  private String name;

  /**............................................................

     constructors, getters and setters ....

     ............................................................*/
}

尝试获取用户修订的功能如下

@Override
public List<UserVO> findAllRevisions(Long id) {
  AuditReader reader = AuditReaderFactory.get(entityManager);
  AuditQuery query = reader.createQuery().forRevisionsOfEntity(UserVO.class, true, true);
  query.add(AuditEntity.id().eq(id));
  List revisions = query.getResultList();

  List<UserVO> users = new ArrayList<>();
  for(Object rev : revisions) {
    UserVO userRev = (UserVO) rev;
    for(UserOrgVO userOrgRev : userRev.getOrganisations()) {
      System.out.println("user org id: " + userOrgRev.getId());
    }
    users.add(userRev);
  }

  return users;
}

以上函数中的行 userRev.getOrganisations()引发以下异常

ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.hibernate.QueryException: could not resolve property: userid_id of: com.envers.domain.vo.UserOrgVO_AUD [select e__ from com.envers.domain.vo.UserOrgVO_AUD e__ where e__.userid_id = :userid_id and e__.originalId.REVISION_ID.id = (select max(e2__.originalId.REVISION_ID.id) from com.envers.domain.vo.UserOrgVO_AUD e2__ where e2__.originalId.REVISION_ID.id <= :revision and e__.originalId.id = e2__.originalId.id) and REVISION_TYPE != :delrevisiontype]] with root cause
org.hibernate.QueryException: could not resolve property: userid_id of: com.envers.domain.vo.UserOrgVO_AUD
at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:62)
at org.hibernate.persister.entity.AbstractPropertyMapping.toType(AbstractPropertyMapping.java:56)
at org.hibernate.persister.entity.AbstractEntityPersister.toType(AbstractEntityPersister.java:1764)
at org.hibernate.hql.internal.ast.tree.FromElementType.getPropertyType(FromElementType.java:393)
at org.hibernate.hql.internal.ast.tree.FromElement.getPropertyType(FromElement.java:505)
at org.hibernate.hql.internal.ast.tree.DotNode.getDataType(DotNode.java:660)
at org.hibernate.hql.internal.ast.tree.DotNode.prepareLhs(DotNode.java:264)
at org.hibernate.hql.internal.ast.tree.DotNode.resolve(DotNode.java:204)
at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:109)
at org.hibernate.hql.internal.ast.tree.FromReferenceNode.resolve(FromReferenceNode.java:104)
at org.hibernate.hql.internal.ast.HqlSqlWalker.resolve(HqlSqlWalker.java:942)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.expr(HqlSqlBaseWalker.java:1283)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.exprOrSubquery(HqlSqlBaseWalker.java:4696)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:4166)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2131)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2056)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:2056)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:810)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:605)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:309)
at org.hibernate.hql.internal.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:257)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:262)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:190)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:142)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:115)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:76)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:150)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:302)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:240)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1894)
at org.hibernate.envers.internal.entities.mapper.relation.query.AbstractRelationQueryGenerator.getQuery(AbstractRelationQueryGenerator.java:55)
at org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.AbstractCollectionInitializor.initialize(AbstractCollectionInitializor.java:49)
at org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.CollectionProxy.checkInit(CollectionProxy.java:33)
at org.hibernate.envers.internal.entities.mapper.relation.lazy.proxy.CollectionProxy.iterator(CollectionProxy.java:57)
at com.envers.service.impl.UserServiceImpl.findAllRevisions(UserServiceImpl.java:79)

您能告诉我envers为什么在UserOrgVO的“ userid”列中添加“ _id”以及如何更正它吗?

感谢与问候,

萨拉特

1 个答案:

答案 0 :(得分:0)

我认为问题出在您的映射上。

您正在尝试定义UserVOUserOrgVO之间的双向映射,但是问题是您仅指定了@OneToMany端而没有指定@ManyToOne谁拥有它。

我认为这样做的原因可能是一种优化,以防止在代码的其他部分加载UserVO实体时Hibernate尝试获取并加载UserOrgVO对象,但这不是正确的处理方式。

从技术上讲,您的映射应如下

public class UserVO {
  ...
  @OneToMany(
    fetch = FetchType.EAGER, 
    mappedBy = "user", 
    cascade = CascadeType.ALL, 
    orphanRemoval = true)
  private List<UserOrgVO> organizations;
}

public class UserOrgVO {
  ..
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "USER_ID")
  private UserVO user;
}

您会发现我在user中将UserOrgVO映射为FetchType.LAZY。这意味着Hibernate应该根据USER_ID列中的值为您创建一个代理,并且只会在首次调用它的getter时获取和水化UserVO实例;从而使它真正变得懒惰。

如果您确实希望将userid也映射为可以在UserOrgVO实体上访问的属性,则可以通过复制{{1 }}实体如下:

USER_ID

这里的警告是,每当您更改UserOrgVO中的@Column(name = "USER_ID", insertable = false, updatable = false) private Long userid; 属性以引用差异用户对象时,都应更新user值,以使其在持久性上下文中保持一致。对于数据库,Hibernate只会根据关联的UserOrgVO实体来设置值,而完全忽略userid中的值。

简而言之,您可以将UserVO视为Hibernate设置的实体的瞬时值,该实体是从数据库中加载的,否则绝对不执行任何操作。从那时起,这完全是信息性的。