在QueryDSL中使用相同的q-object时已经使用了对象

Xel*_*ian 4 java hibernate querydsl

嗨我有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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

错误是:

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)
Run Code Online (Sandbox Code Playgroud)

怎么了?我看到查询不是安全的.但是如何在两种不同的方法中使用Q-class呢?

编辑:

protected JPQLQuery query = new JPAQuery(entityManager);
Run Code Online (Sandbox Code Playgroud)

它是来自ArticleService的受保护变量.

vto*_*tor 5

只要对同一实例的同一生成的QEntityin 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);    
}
Run Code Online (Sandbox Code Playgroud)

在尝试调用此方法时,我们将看到以下异常:

 java.lang.IllegalStateException: qMyEntity is already used
Run Code Online (Sandbox Code Playgroud)

为什么?因为我们有一个实例,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);        
}
Run Code Online (Sandbox Code Playgroud)

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

protected JPQLQuery query = new JPAQuery(entityManager);
Run Code Online (Sandbox Code Playgroud)

例如,每次新的JPAQuery都会得到更改

protected JPQLQuery jpaQuery() {
    return new JPAQuery(entityManager);
}
Run Code Online (Sandbox Code Playgroud)

然后在您的服务实现中

@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);
}
Run Code Online (Sandbox Code Playgroud)

  • 问题不在于生成的 Q-type 对象,而是我们将该 QType 对象与 JPAQuery 的相同实例一起使用了两次(我更新了我的答案以使其更加清晰)。实际上,您将始终拥有一个 Q 类型对象,并且会在任何地方重用它,但是对于 JPAQuery() 的同一个实例,您不能多次重用它。希望有帮助。 (2认同)