1

I have made an application that displays a lot of questions from my database. For this I have made a question entity. I want to be able to "report" a question for being poor/good and so on, so for this I made a feedback entity.

The relationship between these would be: one question may have many feedbacks, and one feedback belongs to one question.

The problem is that when I save the question feedback instance it all maps perfectly in the database, but when I open a question and loops through all the feedbacks none of the feedbacks added is displayed. In order to have them displayed I need to re-deploy the web application.

Why does this happen?

For readability I only show the parts involved

QuestionFeedback entity

public class QuestionFeedback implements Serializable {

    @ManyToOne
    private Question question;
    ....

    public void setQuestion(Question question) {
        this.question = question;

        if (!question.getFeedbacks().contains(this)) {
            question.getFeedbacks().add(this);
        }
    }
    ....
}

Question entity

@Entity
public class Question implements Serializable {

    @OneToMany(mappedBy = "question", fetch = FetchType.EAGER)
    private List<QuestionFeedback> feedbacks;

    public Question() {
        feedbacks = new ArrayList<QuestionFeedback>();
    }

    public void addFeedback(QuestionFeedback questionFeedback) {

        if (!getFeedbacks().contains(questionFeedback)) {
            getFeedbacks().add(questionFeedback);
        }

        if (questionFeedback.getQuestion() != this) {
            questionFeedback.setQuestion(this);
        }
    }
}

Backing bean for the report page

The question entity is already retrieved from the database.

public String flag() {
    questionFeedback.setQuestion(question);
    questionFeedbackService.persist(questionFeedback);

    return "index";
}

DAO class

public void persist(QuestionFeedback questionFeedback) {
    entityManager.persist(questionFeedback);
}
LuckyLuke
  • 47,771
  • 85
  • 270
  • 434
  • If I correctly understand your question, this seems to be a transactional problem as data is correctly stored in the database, correct? If true, it must relate to your entity manager usage (and configuration)... – home Jan 14 '12 at 12:02
  • That is probably true yes. If I refresh the question entity in the find method of my DAO, it works. Seems like it caches it or something. I am using Glassfish with container-managed transactions. – LuckyLuke Jan 14 '12 at 12:03

2 Answers2

2

This is a simple instance of having a dirty session.

Although these can be caused by all sorts of issues, there are usually 2 simple things to keep in mind that will make it very easy to track this bug down .

First you must always remember that, when we persist our data in JPA/hibernate , we don't necessarily have any gaurantee that the transaction has completed in the database. The true meaning of the "persist" method is a common source of errors and questions, make sure you fully understand it and how it relates to your business logic. :

What's the advantage of persist() vs save() in Hibernate?

Second, after you have gauranteed that the transaction has been completed and data has been saved, you can use the EntityManager.refresh method to update the state of any objects from the database.

Community
  • 1
  • 1
jayunit100
  • 17,388
  • 22
  • 92
  • 167
  • That is probably correct, because if I refresh the question entity when after I have used the `EntityManager.find()` it displays all feedbacks. I am using container-managed transaction and Glassfish so shouldn't the persistencecontext flush when the method where my `EntityManager.persist()` ends? And doesn't `EntityManager.find()` fetch the entity from the database? Or are there some cache or something. – LuckyLuke Jan 14 '12 at 12:07
  • This works: `public Question find(Long id) { Question q = entityManager.find(Question.class, id); entityManager.refresh(q); return q;}` – LuckyLuke Jan 14 '12 at 12:09
  • And it also works to merge the question when I persist the question feedback instance. I don't understand it though. – LuckyLuke Jan 14 '12 at 12:31
  • Hmmm... I cant fully grasp all the details. But - I do not believe that your persistance context automatically flushes every time you do a persist. Persist only tells the session that, at some point, the transaction is to be commited - I dont think it forces an immediate commit. – jayunit100 Jan 15 '12 at 03:03
0

You can clear the JPA cache through the following code:

 em.getEntityManagerFactory().getCache().evictAll();

For the record, I always flush after persisting data. Even though your database has the data, I would just try this.

public String flag() {
   questionFeedback.setQuestion(question);
   questionFeedbackService.persist(questionFeedback);
   questionFeedbackService.flush();

   return "index";
}
FAtBalloon
  • 4,500
  • 1
  • 25
  • 33
  • So there is a JPA cache that keeps it as well as the persistence context "cache"? – LuckyLuke Jan 18 '12 at 12:34
  • JPA essentially has two levels of caching. The evictAll() function clears the second level cache or L2 cache. See link for further explanation of JPA caching: http://weblogs.java.net/blog/caroljmcdonald/archive/2009/08/21/jpa-caching – FAtBalloon Jan 19 '12 at 17:21