Quarkus中PanacheRepository的@ManyToMany关联查询报错求助
问题:查询指定Person的关联Message列表时抛出类型不匹配异常
错误日志
2023-05-12 11:19:21,285 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-0) HTTP Request to /persons/1/messages failed, error id: 59165c88-d7d9-470b-99f4-8ca3509f2960-1: java.lang.IllegalArgumentException: Parameter value [Person{id=1, name='abhishek', age=28}] did not match expected type [java.util.Collection (n/a)] at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:54)
相关代码
实体类
@Entity public class Message { @Id @GeneratedValue @Column(name = "message_id") Long id; @Column String messageBody; @JsonManagedReference @ManyToMany private List<Person> person; // getter/setter省略 } @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "person_id") private Long id; @Column(name="person_name") private String name; @Column private int age; @JsonBackReference @ManyToMany(mappedBy = "person", fetch = FetchType.LAZY) private List<Message> messageList; // getter/setter省略 }
仓库类
@ApplicationScoped public class MessageRepository implements PanacheRepository<Message> { } @ApplicationScoped public class PersonRepository implements PanacheRepository<Person> { }
资源类
@Path("/persons") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class PersonResource { @Inject PersonRepository personRepository; @Inject MessageRepository messageRepository; @GET @Path("/{userId}/messages") public Response listAllMessagesOfAUser(Long userId) { Person person = personRepository.findById(userId); List<Message> messagesList = messageRepository.find("person", person).list(); return Response.ok(messagesList).build(); } // 其他方法省略 }
问题原因
错误核心是:Message实体中的person字段是List<Person>类型(多对多关联),当你用messageRepository.find("person", person)查询时,Hibernate会认为你要匹配整个集合,因此期望参数是Collection类型,但你传入的是单个Person对象,导致类型不匹配。
解决方法
方法1:直接利用Person实体的关联关系(最简单)
既然Person实体已经通过mappedBy定义了和Message的反向关联,直接调用person.getMessageList()就能拿到对应的消息列表:
@GET @Path("/{userId}/messages") public Response listAllMessagesOfAUser(Long userId) { Person person = personRepository.findById(userId); // 直接使用实体的关联属性 return Response.ok(person.getMessageList()).build(); }
注意:因为
messageList是LAZY加载,Quarkus中JAX-RS方法默认是事务性的,无需额外配置即可触发关联加载。
方法2:修改查询语句,正确匹配单个Person
如果一定要通过MessageRepository查询,需要调整JPQL的写法:
- 方式A:使用
member of关键字判断Person是否在Message的关联集合中
List<Message> messagesList = messageRepository.find("?1 member of person", person).list();
- 方式B:使用JOIN查询
List<Message> messagesList = messageRepository.find("SELECT m FROM Message m JOIN m.person p WHERE p = ?1", person).list();
- 方式C:直接通过Person的ID查询(更高效)
List<Message> messagesList = messageRepository.find("person.id", userId).list();
额外优化:规范实体字段命名
Message中的person字段是集合类型,建议改成复数persons,避免语义混淆,同时修改Person实体中mappedBy的对应值:
// Message类中 @JsonManagedReference @ManyToMany private List<Person> persons; // Person类中 @JsonBackReference @ManyToMany(mappedBy = "persons", fetch = FetchType.LAZY) private List<Message> messageList;
内容的提问来源于stack exchange,提问作者abhishek narayan
相关产品推荐
相关产品推荐

