I’m a newbie in Spring. I think it’s better to explain my problem with a little example. Let’s say I have two main classes: User and Group. A User can be part of more Groups and a Group, obviously, can have more Users. So the relationship between them is many-to-many. What I would like to show, is something like this (using JSTL):
<c:forEach items="${groups}" var="group">
<c:out value="${group.name}"/> (<c:out value="${fn:length(group.users)}" />):<br />
<c:forEach items="${groups.users}" var="user">
<c:out value="${user.name}"/><br />
</c:forEach><br />
</c:forEach>
Basically, the output should be something like:
Random (2):
Joe
BloggsStar wars (5):
Luke
Chewbacca
Darth Vader
Princess Leia
YodaNintendo (3):
Super Mario
Metroid
Zelda
I initially coded it with the classic @ManyToMany annotation, using an additional table user_has_group (created and managed by JPA) and it was working perfectly.
I needed to modify the structure since I needed the user_has_group table to have the joined_date column. To achieve it, I read online that the best solution is to create another class (i.e. UserHasGroup) and add the one-to-many relationships to this class from User and group. Doing so, it’s possible to add additional attributes to the UserHasGroup class (and therefore additional columns to the user_has_group table). Something like:
User:
@Entity
@Table(name = "user")
public class User
{
@Id
@GeneratedValue
@Column
private int id;
@Column
private String alias;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private List<UserHasGroup> userHasGroup = new ArrayList<UserHasGroup>();
// Constructors/getters/setters
}
Group:
@Entity
@Table(name = "`group`")
public class Group
{
@Id
@GeneratedValue
@Column
private int id;
@Column
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "group")
private List<UserHasGroup> userHasGroup = new ArrayList<UserHasGroup>();
// Constructors/getters/setters
}
UserHasGroup:
@Entity
@Table(name = "user_has_group")
public class UserHasGroup
{
@Id
@GeneratedValue
@Column
private int id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "group_id")
private Group group;
@Column
@Temporal(TemporalType.DATE)
private Date joinedDate;
// Constructors/getters/setters
}
So far, so good. All the tests run successfully and the functionality is maintained.
But I’m facing a problem with JSTL. In fact, with this new structure is obviously not possible to do group.users to iterate through the users.
What is the best way to reach the same functionality as before but with this new structure?
Thank you.
I don’t see a reason why ${fn:length(group.userHasGroup)} should’n work.
The only problem you might come accross is some no active session exception. You can solve it either by
using “open session in view” interceptor (which somebody calls an anti-pattern)
manualy iterating through the list in your service method
eager fetching the relationship – i would be very carefull here as this can lead to many queries to database
Answer to additional question:
It should look somehow like this: