JPA Query Returning Same Result for different Parameter

偶尔善良 提交于 2020-12-05 11:58:29

问题


I'm running into an issue where my query method is in a foreach loop, and each time I'm passing in a different parameter to retrieve different information. However, after the FIRST iteration of the loop, the query data gets cached (I think) and returns the same data for subsequent loops.

Here is my code:

@Transactional(readOnly = true)
public List<InitiativeReport> getInitiativeReports() throws Exception {
try {
    List<InitiativeReport> ir = new ArrayList<InitiativeReport>();
    List<Initiative> in = initiativeRepository.findAll();
    for(Initiative i : in) {
        i.getTheme().getId(); // lazy initialize

        InitiativeReport report = new InitiativeReport();
        report.setId(i.getId());
        report.setInitiativeId(i.getInitiativeId());
        report.setName(i.getName());
        report.setTheme(i.getTheme());

        // this is the call to the query, which is cached after the first iteration
        List<InitiativeProfileQuestion> q = initiativeProfileQuestionRepository.getQuestionsAndAnswerLogs(i.getInitiativeId());
        report.setQuestions(q);
        ir.add(report);
    }

    return ir;
}
catch (Exception e) {
    throw new Exception(e);
}

Here is my repository interface:

public interface InitiativeProfileQuestionRepository extends JpaRepository<InitiativeProfileQuestion, Long> {
    @Query("select distinct q from InitiativeProfileQuestion q "
         + "left join fetch q.answers "
         + "left join fetch q.answerLogs al "
         + "where al.initiative.initiativeId = ?1 "
         + "and al.revision = al.initiative.revision 
         + "order by q.question asc")
    public List<InitiativeProfileQuestion> getQuestionsAndAnswerLogs(String initiativeId);
}

Here is my application.yml file:

spring:
    datasource:
        dataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlDataSource
        url: jdbc:mysql://localhost/testdb
        username: root
        password: XXXXXXXXX
        driverClassName: com.mysql.jdbc.Driver
        testOnBorrow: true
        validationQuery: SELECT 1
    jpa:
        database-platform: org.hibernate.dialect.MySQLInnoDBDialect
        database: MYSQL
        openInView: false
        show_sql: true
        generate-ddl: false
        hibernate:
            ddl-auto: none
            naming-strategy: org.hibernate.cfg.EJB3NamingStrategy

The issue is very similar to a post I found here: Native Query (JPA ) not reset and return the same old result

However, that user is using EntityManager and I have no implementation for EntityManager in my application- I'm letting JPA do all the work and only have query annotations.

Any assistance would be appreciated!


回答1:


Little late to the party but for those finding this now here is what you need to do to solve the issue:

When your querying in a loop that has already started a transaction you need to detach the entities returned from queries inside that loop that share the same id but may have different data.

Heres an example:

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private ProductWarehouseRepository productWarehouseRepository;

    @Autowired
    private EntityManager entityManager;

    @Transactional
    public List<Product> getProducts(){
        List<Product> products = this.productRepository.findAll();
        products.forEach(product -> {
            List<ProductWarehouse> warehouses = this.productWarehouseRepository.findAllByProductId(product.getId());
            warehouses.forEach(warehouse -> {
                //THIS IS THE IMPORTANT PART
                //You have to detach the entity from the session
                this.entityManager.detach(warehouse);
            });
            product.setWarehouses(warehouses);
        });
        return products;
    }
}

In this example product A can be in warehouse id 1, and so can product B, but they may have different quantities available in the warehouse.

You have to detach the entities from the session when the results returned may have collisions on the @Id column. This has to do with the way level 1 caching works in Hibernate. You can check out this link for a little more info http://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/objectstate.html




回答2:


I ran into a very similar problem. I resolved it by changing my Entity class to add an additional @Id annotation to accurately reflect the composite primary key on the database table. You may want to give that a try.

Alternatively, take a look at my recent answer to the question you mention above (Native Query (JPA ) not reset and return the same old result). As you note, it has some similarities to this question.

Also, your InitiativeProfileQuestion shows @Id on variable id. Looks like you are querying by initiativeId. Perhaps you should be querying by id since it's annotated as the primary key.

Note: I don't understand why someone deleted this initially as not answering the question. I tried posting it as a comment, but I don't have enough reputation points to do so. Nonetheless, I do believe what I'm suggesting may resolve the questioner's problem, so I consider it an answer. I grant that it could be interpreted more as suggestions than an answer. But in truth I wouldn't call it strictly a comment, either. Shouldn't the questioner be the one to weigh in on whether it's an answer? And does my answer really fall into any of these criteria?: https://stackoverflow.com/help/deleted-answers.




回答3:


I had the same problem, and I searched many web pages, and couldn't found an exact solution. Then I found the following approach can solve the problem.

Calling entityManager.clear() before querying can resolve this problem.



来源:https://stackoverflow.com/questions/32527978/jpa-query-returning-same-result-for-different-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!