java - 在 QueryDSL 中使用相同的 q-object 时对象已被使用

标签 java hibernate querydsl

您好,我有一个带有 QUeryDSL 3.6.0 的 Hibernate 项目,当我的服务类中只有 findAll() 方法时,一切正常。但是当我添加 findByID 时出现错误。

    public class ArticleServiceImpl extends ArticleService {

        QArticle article = QArticle.article;

        @Override
        public List<Article> findAll() {
            return query.from(article).fetchAll().list(article);
        }

        public Article findById(@Nonnull final long id) {
            return query.from(article).where(article.id.eq(id)).uniqueResult(article);
        }
    }

错误是:

Exception in thread "main" java.lang.IllegalStateException: article is already used
    at com.mysema.query.DefaultQueryMetadata.addJoin(DefaultQueryMetadata.java:160)
    at com.mysema.query.support.QueryMixin.from(QueryMixin.java:189)
    at com.mysema.query.jpa.JPAQueryBase.from(JPAQueryBase.java:88)
    at com.mysema.query.jpa.JPAQueryBase.from(JPAQueryBase.java:32)
    at com.example.hibernate.services.ArticleServiceImpl.findById(ArticleServiceImpl.java:30)
    at com.example.hibernate.core.Main.main(Main.java:42)

会发生什么?我看到查询不是安全的。但是如何在两种不同的方法中使用Q-class呢?

编辑:

protected JPQLQuery query = new JPAQuery(entityManager);

它是来自 ArticleService 的 protected 变量。

最佳答案

只要对同一生成的 QEntity 进行可重复调用,就会抛出此异常。在 from() JPAQuery() 的同一实例的子句.

这是一个例子(免责声明:这将是一个非常非常愚蠢的例子,只是为了说明问题)。

假设我们有一个名为 MyEntity 的实体,我们尝试得到两个 MyEntity以某种方式来自数据库,第一个结果将针对给定的 id , 第二个结果将是 id+1

public List<MyEntity> findMyDumbEntities(long id) {    
      QMyEntity qMyEntity = QMyEntity.myEntity;
      JPAQuery jpaQuery = new JPAQuery(entityManager);
      MyEntity myFirstEntity = jpaQuery.from(qMyEntity).where(qMyEntity.id.eq(id)).uniqueResult(qMyEntity);
      MyEntity mySecondEntity = jpaQuery.from(qMyEntity).where(qMyEntity.id.eq(id+1)).uniqueResult(qMyEntity);

      return Arrays.asList(myFirstEntity, mySecondEntity);    
}

当尝试调用这个方法时,我们会看到以下异常:

 java.lang.IllegalStateException: qMyEntity is already used

为什么?因为我们有一个 JPAQuery 的实例我们正在重复调用同一个实体(我们有两个 jpqQuery.from(qMyEntity) )。为了解决这个问题,我们只需要在每次查询时获取 JPAQuery 实例,所以我们需要将代码更改为

public List<MyEntity> findMyDumbEntities(long id) {        
          QMyEntity qMyEntity = QMyEntity.myEntity;
          MyEntity myFirstEntity = new JPAQuery(entityManager).from(qMyEntity).where(qMyEntity.id.eq(id)).uniqueResult(qMyEntity);
          MyEntity mySecondEntity = new JPAQuery(entityManager).from(qMyEntity).where(qMyEntity.id.eq(id+1)).uniqueResult(qMyEntity);

          return Arrays.asList(myFirstEntity, mySecondEntity);        
}

所以要解决你的问题,而不是让 JPQQuery 初始化一次

protected JPQLQuery query = new JPAQuery(entityManager);

例如每次新的 JPAQuery 时你得到的变化

protected JPQLQuery jpaQuery() {
    return new JPAQuery(entityManager);
}

然后在你的服务实现中

@Override
public List<Article> findAll() {
      return jpaQuery().from(article).fetchAll().list(article);
}

public Article findById(@Nonnull final long id) {
      return jpaQuery().from(article).where(article.id.eq(id)).uniqueResult(article);
}

关于java - 在 QueryDSL 中使用相同的 q-object 时对象已被使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28649876/

相关文章:

java - flexmojo java堆空间错误

mysql - Mysql中long varchar的最大限制是多少

java - 是否可以在 tomcat 7 中的同一端口上运行多个 Web 应用程序

hibernate - QueryDsl 交叉联接返回零个元素

c# - 将 BCD 转换代码从 Java 迁移到 .Net

部署到 weblogic 时出现 Java LinkageError

java - 我选择 NetBeans 而不是 Eclipse 是否正确?

java - 为什么 Hibernate 会查询两次?

java - Querydsl 不支持 rand() 吗?

"update myTable where myColumn in (' 有趣的 Java QueryDsl', 'values' )”?