返回null而不是org.hibernate.ObjectNotFoundException: Java



我有一个名为ad_session的表,它记录用户会话。我使用Java从该表中获取所有成功会话的列表。然后循环遍历该列表以获取每个会话的用户(这是ad_user表的外键)。然后获取属于该用户的客户端,并将该客户端添加到列表中。然而,其中一个用户不再存在,所以我的代码停止运行,并抛出以下异常:

org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [ADUser#76A5C22E6D2446A399AE9AD7C1DED0C7]

这是我的原始代码:


List<Session> sessions = getAllSuccessfulSessionsInTable();
List<Client> clientsForThatDay = new ArrayList<>();
try {
for (Session session : sessions) {
//code fails when trying to get the non-existent user:
User user = session.getCreatedBy();
Client userClient = user.getClient();
clientsForThatDay.add(userClient);
}
} catch (Exception e) {     
log.error("Error getting client from user: ", e);
}

我假设当获得不存在的记录时,它将返回null,所以这就是我尝试的:

List<Session> sessions = getAllSuccessfulSessionsInTable();
List<Client> clientsForThatDay = new ArrayList<>();
//Create new user object to stand in place of the non-existent user
User deletedUser = new User();
deletedUser.setName("Deleted User");
//Create new client object to stand in place of the non-existent client
Client deletedUserClient = new Client();
deletedUserClient.setName("Unknown Client");
try {
for (Session session : sessions) {
//check is User is null, if it is, use the deletedUser object, otherwise, use the existing user
User user = session.getCreatedBy() == null ? deletedUser : session.getCreatedBy();

Client userClient = user.getName().equals("Deleted User") ? deletedUserClient : user.getClient();
clientsForThatDay.add(userClient);
}
} catch (Exception e) {
log.error("Error getting client from user: ", e);
}

然而,它不是返回null,它只是抛出异常,然后停止。我怎么能让它返回null在这里,所以我可以处理丢失的记录没有我的代码停止?谢谢你的建议。

您的数据库似乎缺少一个外键约束。这意味着映射User的表对Client表中不再存在的行有引用。

只有当客户端被删除而没有更新用户表时才会发生这种情况。解决方案是在表之间添加一个外键约束。

请记住,如果表中的数据不正确,当Hibernate加载实体User时,它也会认为存在一个客户端。这意味着User#getClient不会为空,并且代码中有user.getClient() == null之类检查的每个地方都将失败。try-catch方法不会帮助您解决这个问题(除非您将关联设置为null,以防出现错误,我猜)。

我能想到的解决办法:

  1. 添加外键约束(imho,最好的解决方案)
  2. 不要映射关联,映射client_id作为一个属性,并使用第二个查询或查找加载客户端(我只会这样做,如果你不能更新数据库)
    class User {
    @Column(name = "client_id")
    Long clientId;
    }
    User user = ...
    Client client = session.find(Client.class, user.getClientId());
    
  3. 你可以通过session.find(Client.class, user.getClient().getId())加载客户端并设置与结果的关联:
    User user = //...
    Client client = session.find(Client.class, user.getClient().getId());
    user.setClient(client);
    
  4. User中不映射关联,并运行本地SQL查询来加载客户端:
    User user = ...
    String sql = "select * from Client c join User u on c.id = u.client_id where u.id = :uid";
    Client client = session.createNativeQuery(sql, Client.class)
    .setParameter("uid", user.getId())
    .getSingleResultOrNull();
    

您可以选择最适合您的方法,但请记住,映射没有外键约束的关联将导致各种类型的一致性问题。

我决定选择3,只是因为有时人们在工作中会遇到一些不可能的情况,但我不建议这样做。

最新更新