我正在使用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”以及如何更正它吗?
感谢与问候,
萨拉特
答案 0 :(得分:0)
我认为问题出在您的映射上。
您正在尝试定义UserVO
和UserOrgVO
之间的双向映射,但是问题是您仅指定了@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设置的实体的瞬时值,该实体是从数据库中加载的,否则绝对不执行任何操作。从那时起,这完全是信息性的。