Hibernate多对多关系查询没有其集合元素的实体

Hibernate many-to-many relationship query the Entity without its collection elements

描述:我在 User 和 Shoplist 实体之间建立了多对多关系。我正在休息 api,我只想在有人对 /users/{id} 进行 GET 时查询用户。如果我尝试从数据库中获取用户,它会说购物清单的集合没有初始化,但这正是我想要的,只有没有他的购物清单的用户。如果我得到用户的购物清单,它工作正常,但这不是我想要的。

我的实体:

User.java

@Entity
public class User implements Serializable {
@Id
@GeneratedValue
private int id;

private String name;

private String lastname;

@Column(nullable = false)
private String email;

private String password;

@Column(nullable = true) //maybe set @ColumnDefault()
private URL avatar;


@JsonIgnoreProperties("users")
@JoinTable(
        name = "User_Shoplist",
        joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "shoplist_id", referencedColumnName = "id")
)
@ManyToMany
private Set<Shoplist> shoplists = new HashSet<>();

// getters and setter

Shoplist.java

@Entity
public class Shoplist implements Serializable {
@Id
@GeneratedValue
private int id;
private String name;


@JsonIgnoreProperties("shoplists")
@ManyToMany(mappedBy = "shoplists")
private Set<User> users = new HashSet<>();

// getters and setter

Controller.java

@GET
@Produces(MediaType.APPLICATION_JSON)
public Response index() {
    SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
    Session session = sessionFactory.openSession();

    try {
        session.beginTransaction();
        User u1 = session.get(User.class, 1);
        session.getTransaction().commit();
        session.close();

        return Response.status(200).entity(u1).build();
    } catch(Exception e) {
        session.getTransaction().rollback();
        return Response.status(Response.Status.BAD_REQUEST).build();
    }

}

目标 :正如我之前所说,我想 return 关于用户的信息,但没有他的所有购物清单。

当您的实体序列化为 JSON 时,将调用所有 getter(包括 getShoplists),并且因为这是在事务之外发生的,所以您会得到 LazyInitializationException。这是实体对象永远不应该离开服务的原因之一。

您需要创建 DTO(数据传输对象),仅分配您需要发送的那些值(所有仍在交易中的值),然后发送 dto 而不是实体。

例如

public class UserDto {
  private int id;
  private String name;
  private String lastname;
  private String email;
  // btw, this is probably not a good idea to send user password to the client
  // ...
  // getters and setters
}
  session.beginTransaction();
  User u1 = session.get(User.class, 1);

  UserDto dto = new UserDto();
  dto.setName(u1.getName());
  // map other values

  session.getTransaction().commit();
  session.close();

  return Response.status(200).body(dto).build();

Baeldung's tutorial on this using ModelMapper

A good alternative (Mapstruct)