嗨,我有一个带有QueryDSL 3.6.0的Hibernate项目,当我在服务类中只有findAll()方法时,everything一切正常。但是,当我添加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的受保护变量。

最佳答案

每当在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);
}

10-01 19:16