Hibernate returns duplicate because another table has duplicate values
Asked Answered
A

1

6

So I have a Users table, Projects table and User_Roles table. I have one users which is connected to 2 projects, but when I have just one role for him it returns those 2 projects, but if I have 2 roles for him it returns 4 roles (2x2 projects). How do I prevent this

This is my code for returning the list of projects for user

@Override
public List<Project> retrieve(User user) {
    Criteria criteria = super.createCriteria();
    criteria.addOrder(Order.desc("date"));
    criteria.createCriteria("users").add(Restrictions.eq("id", user.getId()));

    return (List<Project>) criteria.list();
}

mappings in User class

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "Users_Projects",
           joinColumns = @JoinColumn(name = "UserID"), inverseJoinColumns =   @JoinColumn(name = "ProjectID"))
public List<Project> getProjects() {
    return projects;
} 

@ElementCollection(fetch = FetchType.EAGER)
@Enumerated(EnumType.STRING)
@Column(name = "RoleType")
@JoinTable(name = "User_Roles", joinColumns = @JoinColumn(name = "UserID"))
public Set<Role> getRoles() {
    return roles;
}

Any suggestions what is the problem here?

tnx

Adriene answered 3/7, 2012 at 21:41 Comment(0)
T
14

The classic "fix" for issues of duplicate rows from criteria queries, which will likely work as long as you're not trying to combine it with pagination, is to add

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

I believe this is happening in your situation because of the eager loading of the user roles. Changing that to be lazy might also work, and continue to work if you need pagination.

Setting fetch = FetchType.EAGER instructs hibernate that you want to always load all the roles for the user whenever you retrieve a user, which it accomplishes by always doing a join to the roles table.

Unfortunately, that sql leads to multiple records with the same user (one for each role), and it then has to be straightened out in Java after the sql is run, which is what the result transformer does.

Much more unfortunately, if you want to use paging in the most natural way with simple hibernate criteria, using criteria.setFirstResult and criteria.setMaxResults, things happen in the wrong order, so these queries that need the result transformer to avoid duplicates just don't page right.

To understand all the hibernate sql generation a bit better, I'd advise turning on logging of the generated sql as described in this answer to another SO hibernate question.

Titanothere answered 3/7, 2012 at 22:14 Comment(2)
thank you! worked like a charm, can you however explain why would the loading of the roles lead to this. I am also sure that this is the case, but I just dont follow why would setting something that is not part of the connection of the users-projects cause this. Any thoughts?Adriene
See my update for a bit more on the question in your comment.Titanothere

© 2022 - 2024 — McMap. All rights reserved.