1

I have three tables and I want to map all data in them into List of entities, each containing List of another entities.

  user     user_role
 ┌─────┐1 ┌──────────┐   role
 │ id  ├──┤ user_id  │* ┌─────┐
 ├─────┤ *│ role_id  ├──┤ id  │
 │name │  ├──────────┤ 1├─────┤
 └─────┘  │ given_by │  │name │
          └──────────┘  └─────┘

I want to map it's data to List of UserWithRolesAndGivers. Entities are below.

public class UserWithRolesAndGivers {
  private String userName;
  private List<RoleAndGiver> roleAndGivers;
}
public class RoleAndGiver {
  private String roleName;
  private String givenBy;
}

How can I achieve this using hibernate?

Xstian
  • 8,184
  • 10
  • 42
  • 72
Alexey
  • 35
  • 5

1 Answers1

1

That would look something like the below. You need a Join entity 'UserRole' as you are recording additional information (given_by) in the user_role table. So, rather than using a @ManyToMany between User<>Role you map a @OneToMany using this third entity.

@Entity
public class User{

    @Id
    private Long id;

    @Column(name = "name")
    private String name;

    @OneToMany(mappedBy = "user")
    public List<UserRole> userRoles;
}

@Entity
public class UserRole{

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne
    @JoinColumn(name = "role_id")
    private Role role;

    @Column(name = "given_by")
    private String givenBy;
}

@Entity
public class Role{

    @Id
    private Long Id;

    @Column(name = "name")
    private String name;

    @OneToMany(mappedBy = "role")
    private List<UserRole> userRoles;
}
Alan Hay
  • 22,665
  • 4
  • 56
  • 110
  • I just tried to project your models onto my model using criteria and projections, but even selection resulted in fail. Code `session.createCriteria(User.class).list()` returns only list of users, but code `session.createCriteria(User.class).setFetchMode("userRoles", FetchMode.JOIN).list()` causes org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError) – Alexey Dec 16 '15 at 17:54
  • Saying it fails without giving any further details isn't really going to get you much help! – Alan Hay Dec 16 '15 at 17:56
  • I pressed enter too early, so I had to add explanation later. Please take a look. – Alexey Dec 16 '15 at 18:03
  • Well that is a totally separate JSON mapping issue. A quick Google gives the solution here; http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion – Alan Hay Dec 16 '15 at 18:14
  • Thanks, i managed to implement it! Now I can select related data by `session.createCriteria(User.class, "u").createAlias("userRoles", "ur").createAlias("ur.role", "r").setProjection(Projections.projectionList().add(Projections.property("u.name"), "userName").add(Projections.property("r.name"), "roleName").add(Projections.property("ur.givenBy"), "givenBy")).list()` I'll have to group results in memory as described here http://stackoverflow.com/questions/11852230/adding-a-projection-to-a-list-in-hibernate but that seems lesser evil to me. – Alexey Dec 16 '15 at 20:08
  • I'm sure you could add a method to User, say, getRoles() which Iterates the collection userRoles and returns a List. Add a simple Jackson annotation to this and then all you need to do is load a user and pass that to Jackson rather than doing all that projection stuff. – Alan Hay Dec 16 '15 at 20:44