我有一个从数据库中获取数据的服务,该数据库具有以加密值存储的列。
从DAO中获取后,我将把属性的值更新为解密后的值,然后将其作为API的响应发送。
我认为该实体已为选择查询启用了更改跟踪,这也是因为获取数据后,将使用解密的密码在数据库中更新数据。我已经搜寻了一下,发现使用EntityManager
解决了问题,但是对于此实现,我必须在许多实体中进行很多代码更改。
从这个链接,我看到我们必须编写自定义的无状态bean并注入代码,但是看起来不正确。请向我建议解决此问题的最佳方法。
我的DAO:
@Repository
public interface EnvironmentDao extends JpaRepository<Environment, Long> {
//自定义方法与本地查询一起使用
}
我的服务
@Override
public List<Environment> getEnvironmentsByIds(List<Long> environmentIds) throws Exception {
if (environmentIds == null || environmentIds.size() < 1) {
return null;
}
return decryptPassword(environmentDao.findAllById(environmentIds));
}
在cryptoPassword方法内部,我只是遍历所有记录,然后设置解密密码,例如
e.setDB_Password(encryptionService.decrypt(e.getDB_Password()));
我昨天注意到的一个案例是,对于任何错误的类似实体,都有一个数据库保存,并且该值得到了更新,因此,在更正错误之后,此更改就没有发生。
请帮助我,因为我不是Java方面的专家,并且需要花费更多时间进行分析并且无法理解。在C#的情况下,我会使用
.AsNoTracking()
,但是我对Java的了解并不多,而且四处游荡。在服务中尝试了以下内容
@Autowired
EntityManager entityManager;
在方法中
Optional<Environment> environment = environmentDao.findById(id);
entityManager.detach(environment.get());
return managePassword(environment.get(), false);
最佳答案
我建议两种选择来克服无意中更新的实体:
我建议不要创建实体DTO类并创建该类的实例,然后将相关属性设置到DTO实例上,而不是返回实体本身,这样就不会对实体本身进行任何更改。因此,代码将如下所示:
public List<EnvironmentDTO> getEnvironmentsByIds(List<Long> environmentIds) throws Exception {
if (environmentIds == null || environmentIds.size() < 1) {
return null;
}
return createEnvironmentDTOs(environmentDao.findAllById(environmentIds));
}
private LisT<EnvironmentDTO> createEnvironmentDTOs(List<Environment> environments) {
return environments.stream().map((env) -> {
EnvironmentDTO envDto = new EnvironmentDTO();
// Copy all relevant fields to DTO (you can even use some Mapper library for this, i.e. http://modelmapper.org/)
envDto.setDB_Password(encryptionService.decrypt(e.getDB_Password()));
})
}
如果您想返回实体,无论如何,而不是从实体创建DTO类和实例;您可以分离实体,以便对实体所做的更改不会反映到数据库中。因此,解密密码并将其设置回实体后,您需要做的是detaching实体:
entityManager.detach(environment)