我正在用JavaEE为一个管理房间预订的应用程序开发REST API。我有以下问题:
我的应用程序有3个实体类:
@Entity
public class Reservation {
@GeneratedValue
@Id
private Integer id;
@ManyToOne
@JoinColumn(name="room_id")
private Room room;
private LocalDateTime reservationStart;
private LocalDateTime reservationEnd;
@ManyToOne
@JoinColumn(name="user_id")
private User user;@Entity
public class Room {
@GeneratedValue
@Id
private Integer id;
private String description;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "room")
private List<Reservation> reservations;
}@Entity
public class User {
@Id
@GeneratedValue
private Integer id;
private String firstName;
private String surname;
private UserRole role;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private List<Reservation> reservations;
}在使用JPA的DAO中的一个查询中,我希望检索属于用户的所有数据:个人数据、用户的预订和每个预订的房间详细信息,而不创建无限数量的嵌套对象:
{
"user": {
"id": "id",
"firstname": "name",
"lastname": "lastname",
"email": "email",
"Reservations": [
{
"id" : "1234",
"startdate": "S",
"stopdate": "date",
"room": {
"id": "id",
"description": "somedescription"
}
},
{
"id" : "2134",
"startdate": "S",
"stopdate": "date",
"room": {
"id": "id",
"description": "description"
}
}
]
}
}天真的方法:
public User read(Integer id) {
return entityManager.find(User.class, id);
}显然返回LazyInitializationError,预留以PersistentBag而不是List的形式返回,因为它们不是初始化的。
public User read(Integer id) {
User user = entityManager.find(User.class, id);
user.getReservations();
return user;
}返回相同的值。
也是如此:
public User read(Integer id) {
Query query = entityManager.createQuery("select u from User u " +
"join fetch u.reservations r " +
"where u.id = :id");
query.setParameter("id", id);
Object singleResult = query.getSingleResult();
return (User) singleResult;
}切换到FetchType.Eager以RESTEASY008205: JSON绑定序列化错误java.lang.StackOverflowError结束,我认为这是因为yasson试图做无限深的嵌套JSON。
我不想在@ManyToOne关系上使用@JsonbTransient注释,因为我还希望能够检索属于某个房间的所有预订,例如按日期过滤,并在这些预订中包含预订它们的人的信息,因此我需要这些字段。
我可以使用一个简单的SQL查询来检索数据(在控制台):
select * from User
LEFT JOIN Reservation as reservation on user_id = reservation.user_id
LEFT JOIN Room as room on reservation.room_id = room.id
WHERE User_id = 1但是entityManager.createNativeQuery返回了
NonUniqueDiscoveredSqlAliasException: Encountered a duplicated sql alias [id] during auto-discovery of a native-sql queryJAX-RS端点被标记为事务性。它有一个直接注入的DAO对象,而DAO对象又有一个注入的EntityManager。我使用的是JBOSS 20.0.1FINAL,Hibernate 5.4.9,JAVAEE 8.0.1,Java 1.8。
也许这只是一个好的JPQL查询的问题,但到目前为止,我已经花了两天多的时间在它上面,仍然不能让它工作(但学到了很多关于调试Hibernate的知识),所以任何帮助都将不胜感激。
发布于 2021-04-28 16:30:00
通常这是通过引入DTO来解决的,我认为这是Blaze-Persistence Entity Views的一个完美用例。
我创建了这个库,以便在JPA模型和自定义接口或抽象类定义的模型之间轻松映射,就像Spring数据在类固醇上的投影一样。其思想是以您喜欢的方式定义目标结构(域模型),并通过JPQL表达式将属性(Getter)映射到实体模型。
使用Blaze-Persistence实体视图,您的用例的DTO模型可能如下所示:
@EntityView(User.class)
public interface UserDto {
@IdMapping
Integer getId();
String getFirstname();
String getLastname();
String getEmail();
Set<ReservationDto> getReservations();
@EntityView(Reservation.class)
interface ReservationDto {
@IdMapping
Integer getId();
@Mapping("reservationStart")
LocalDateTime getStartdate();
@Mapping("reservationEnd")
LocalDateTime getEnddate();
RoomDto getRoom();
}
@EntityView(Room.class)
interface RoomDto {
@IdMapping
Integer getId();
String getDescription();
}
}查询就是将实体视图应用于查询,最简单的就是通过id进行查询。
UserDto a = entityViewManager.find(entityManager, UserDto.class, id);
Spring数据集成允许您像使用Spring数据投影一样使用它:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<UserDto> findAll(Pageable pageable);最好的部分是,它将只获取实际需要的状态!
https://stackoverflow.com/questions/67259199
复制相似问题