3

I stumbled on a problem with merge method of EntityManager.

I have this class

@Entity
public class QuestionList {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String name;

    @ManyToOne
    private UserEntity user;

    @OneToMany(cascade = CascadeType.ALL)
    private List<QuestionUnit> units = new ArrayList<QuestionUnit>();

    public List<QuestionUnit> getUnits() {
        return units;
    }

    public void setUnits(List<QuestionUnit> units) {
        this.units = units;
    }

    public Long getId() {
        return id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void addQuestionUnit(QuestionUnit QuestionUnit) {
        this.units.add(QuestionUnit);
    }

    public void setUser(UserEntity user) {
        this.user = user;
    }

    public UserEntity getUser() {
        return this.user;
    }

}

now, if I just modify one of the objects in units the merge is fine, but if I delete or add new object to the collection, the way that merge happens is that I am getting delete from QuestionList_QuestionUnit where QuestionList_id=? and then every row is added one by one insert into QuestionList_QuestionUnit (QuestionList_id, units_id) values (?, ?)

I am wondering, is it possible to tell JPA/Hibernate to just add/delete the row associated with the object added/deleted? Or is it the way that merge just works with collections and in my case I need to write my own query for updating the database.

I am asking because this collection can be potentially pretty huge, and just deleting all rows and inserting almost all of them again doesn't seems like a good way to update the table.

EDIT: as requested:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class QuestionUnit {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private long id;

    @OneToOne(cascade = CascadeType.ALL)
    private AnswerUnit correctAnswer;

    public QuestionUnit(AnswerUnit correctAnswer) {
        this.correctAnswer = correctAnswer;
    }

    public void setCorrectAnswer(AnswerUnit correctAnswer) {
        this.correctAnswer = correctAnswer;
    }

    public AnswerUnit getCorrectAnswer() {
        return this.correctAnswer;
    }

    public long getId() {
        return id;
    }

    public void setId(long id){
        this.id=id;
    }

    public abstract Object getQuestionContent();

    public abstract String getTitle();

}

there are 3 concrete classes in this hierarchy, for example

@Question("openQuestion")
@Entity
public class OpenQuestion extends QuestionUnit {

    public void setQuestionContent(String questionContent) {
        this.questionContent = questionContent;
    }

    private String questionContent;

    public OpenQuestion() {
        this(null, new OpenQuestionAnswer());
    }

    public OpenQuestion(String questionContent, AnswerUnit correctAnswer) {
        super(correctAnswer);
        this.questionContent = questionContent;
    }

    public String getQuestionContent() {
        return this.questionContent;
    }

    public String getTitle() {
        return questionContent;
    }
}

@Transactional(propagation = Propagation.REQUIRED)
public void update(QuestionList questionList) {
    entityManager.merge(questionList);
}

this method is used for all updates, because the list is in the detached state.

Andna
  • 6,539
  • 13
  • 71
  • 120
  • Can you include the QuestionUnit class and the code that is doing the delete / add object,merge ? – gkamal Sep 06 '12 at 05:21

1 Answers1

2

It think the problem is caused because of using List instead of Set.

@OneToMany(cascade = CascadeType.ALL)
private List<QuestionUnit> units = new ArrayList<QuestionUnit>();

change to

@OneToMany(cascade = CascadeType.ALL)
private Set<QuestionUnit> units = new HashSet<QuestionUnit>();

Hibernate Many to Many Relations Set Or List?

Community
  • 1
  • 1
gkamal
  • 20,777
  • 4
  • 60
  • 57