NativeQuery查询返回JSON与数据库结果不一致问题排查
问题分析与解决方案
问题1:返回重复用户数据
原因:你的NativeQuery关联了多表(用户→权限→角色→角色菜单→菜单),一个用户对应多条菜单记录,SQL查询结果会返回与菜单数量相同的用户重复行。JPA将每一行结果映射为一个Users实体,最终List里就会出现多个相同的用户对象。
问题2:hakAksesId未正确获取
原因:
- 使用
SELECT *查询时,JPA只会将结果中匹配Users实体字段的列赋值,HAK_AKSES表的HAK_AKSES_ID列不会自动映射到Users的hakAksesId字段(除非实体字段名和列名完全匹配且JPA能识别关联)。 - 当前Users实体的hakAksesId字段若为直接存储的外键,可能因SQL结果列名不匹配、实体映射缺失,导致无法正确赋值。
解决方案
方案一:修正NativeQuery,解决重复与字段映射问题
- 去重处理:在SQL中添加
DISTINCT关键字,过滤重复的用户行。 - 明确指定字段:替换
SELECT *,明确选择需要的字段(包括HAK_AKSES表的HAK_AKSES_ID),确保与Users实体的字段映射匹配。
修改Repository代码:
public interface UsersRepository extends JpaRepository<Users, Long>{ @Query(value="SELECT DISTINCT u.*, h.HAK_AKSES_ID " + "FROM USERS u " + "JOIN HAK_AKSES h ON u.USER_ID = h.USER_ID " + "JOIN ROLES r ON h.ROLE_ID = r.ROLE_ID " + "JOIN ROLE_MENU rm ON r.ROLE_ID = rm.ROLE_ID " + "JOIN MENU m ON rm.MENU_ID = m.MENU_ID " + "WHERE u.EMAIL = :email AND u.PASSWORD = :password ", nativeQuery = true) List<Users> getAll(@Param("email") String email, @Param("password") String password); }
同时确保Users实体的hakAksesId字段标注正确的列名映射:
@Entity @Table(name = "USERS") public class Users { // 其他字段... @Column(name = "HAK_AKSES_ID") // 匹配HAK_AKSES表的主键列名 private Long hakAksesId; // getter/setter }
方案二:使用JPA关联映射+JPQL查询(推荐)
通过实体关联关系替代原生SQL的多表JOIN,让JPA自动处理关联数据,同时避免重复数据问题。
- 配置实体关联:
// Users实体 @Entity @Table(name = "USERS") public class Users { @Id @Column(name = "USER_ID") private Long userId; // 其他用户字段... @OneToOne(fetch = FetchType.EAGER) // 根据实际关系选择@OneToOne/@ManyToOne @JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID") // 关联HAK_AKSES的USER_ID private HakAkses hakAkses; // 新增获取hakAksesId的方法 public Long getHakAksesId() { return hakAkses != null ? hakAkses.getHakAksesId() : null; } // 其他getter/setter } // HakAkses实体 @Entity @Table(name = "HAK_AKSES") public class HakAkses { @Id @Column(name = "HAK_AKSES_ID") private Long hakAksesId; @Column(name = "USER_ID") private Long userId; @ManyToOne @JoinColumn(name = "ROLE_ID") private Roles role; // getter/setter }
- 修改Repository为JPQL查询:
public interface UsersRepository extends JpaRepository<Users, Long>{ @Query("SELECT DISTINCT u FROM Users u " + "JOIN FETCH u.hakAkses h " + "JOIN FETCH h.role r " + "JOIN FETCH r.roleMenus rm " + "JOIN FETCH rm.menu m " + "WHERE u.email = :email AND u.password = :password ") List<Users> getAll(@Param("email") String email, @Param("password") String password); }
DISTINCT用于过滤因多菜单关联产生的重复用户对象,JOIN FETCH用于一次性加载关联实体,避免懒加载问题。
额外修复:Service层toEntity方法的bug
你的toEntity方法中,查询HakAkses的逻辑错误,需修正为:
// 错误:用用户ID查询HakAkses,应该用hakAksesId // Optional<HakAkses> optionalHakAkses = hakAksesRepository.findById(wrapper.getUserId()); // 修正为: Optional<HakAkses> optionalHakAkses = hakAksesRepository.findById(wrapper.getHakAksesId());
内容的提问来源于stack exchange,提问作者Juan Kalyzta
相关产品推荐
相关产品推荐

