You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NativeQuery查询返回JSON与数据库结果不一致问题排查

问题分析与解决方案

问题1:返回重复用户数据

原因:你的NativeQuery关联了多表(用户→权限→角色→角色菜单→菜单),一个用户对应多条菜单记录,SQL查询结果会返回与菜单数量相同的用户重复行。JPA将每一行结果映射为一个Users实体,最终List里就会出现多个相同的用户对象。

问题2:hakAksesId未正确获取

原因:

  1. 使用SELECT *查询时,JPA只会将结果中匹配Users实体字段的列赋值,HAK_AKSES表的HAK_AKSES_ID列不会自动映射到Users的hakAksesId字段(除非实体字段名和列名完全匹配且JPA能识别关联)。
  2. 当前Users实体的hakAksesId字段若为直接存储的外键,可能因SQL结果列名不匹配、实体映射缺失,导致无法正确赋值。

解决方案

方案一:修正NativeQuery,解决重复与字段映射问题

  1. 去重处理:在SQL中添加DISTINCT关键字,过滤重复的用户行。
  2. 明确指定字段:替换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自动处理关联数据,同时避免重复数据问题。

  1. 配置实体关联:
// 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
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 20:45:23