【问题标题】:Spring Data JPA updates entity when I don't want it to当我不想更新实体时,Spring Data JPA 会更新它
【发布时间】:2019-04-04 00:38:24
【问题描述】:

我有一种情况,我想检索数据,但在返回之前我想在不保存/持久化的情况下更改它。

这是我的休息控制器:

@RestController
@RequestMapping("api/drawing-releases")
@CrossOrigin("*")
public class DrawingReleaseRestController {
    @Autowired
    private DrawingReleaseService service;

    @RequestMapping(method = RequestMethod.GET, value = "/{id}")
    @JsonView(View.DrawingReleaseView.class)
    public ResponseEntity<DrawingRelease> getWithId(@PathVariable int id) throws EntityNotFoundException {
      return new ResponseEntity<>(service.getByID(id),HttpStatus.OK);
    }
}

这里是服务实现:

@Service
public class DrawingReleaseServiceImpl extends DrawingFunctions implements DrawingReleaseService {
    /**
     * Logging Manager
     */
    private static final Logger LOGGER=LogManager.getLogger();

    @Autowired
    private DrawingReleaseRepository repository;

    @Override
    public DrawingRelease getByID(int id) throws EntityNotFoundException {
        Optional<DrawingRelease> opt = repository.findById(id);
        ...
        // manipulate the data here
        ...
        return opt.get();
    }
}

最初我在服务上有@Transactional 注释。通过删除它而不在 getByID 方法上使用它,我首先认为会话将​​与存储库一起打开和关闭,如答案 here 所示。

那不起作用,我在 cmets 中看到“会话持续整个 HTTP 请求处理期间”。所以,在我添加的服务中

@Autowired
private EntityManager em;

然后在我添加的getByID方法中

em.close();

在我进行任何更改之前。但是,我所做的任何更改仍在保留中。

有什么方法可以在我的服务层中进行未保存的更改?我想我可以创建一些 POJO 来镜像实体(但不是实体),然后复制数据并返回这些对象,但似乎我不应该做这样的事情。

【问题讨论】:

    标签: java hibernate jpa spring-data-jpa persistence


    【解决方案1】:

    您说您想要获取一个实体,然后更改数据,然后在没有持久化实体的情况下返回它,但恕我直言,您不应该为此使用实体。为什么要更改数据以及用户将如何处理它,因为它不再代表数据库中的内容。还将进行哪些其他更改或哪些其他假设(这是一个数据库对象)将无效?

    如果您使用数据库对象来派生不同的对象,您应该为此目的使用不同的类。这很常见,称为数据传输对象(DTO),它们可以直接使用投影从 spring-data-jpa 创建。您的 Dto 对象会将实体作为构造函数并填写它想要从实体中获取的任何属性。 Dto 不是持久对象,因此保存它没有问题。

    更加清晰易懂的设计,与SOLID Principles and code structure一致。

    【讨论】:

    • 也许我应该进一步研究一下。至于我为什么要这样做——我有一张可以有零件清单的图纸。任何图纸都可用于另一张图纸的零件清单。就其本身而言,一张图可以有部件 1、2 和 3。如果该图是另一个部件列表的一部分,比如在第 12 行,那么我希望它显示为 12、12-1、12-2 和 12 -3。在另一幅图中,它可能在第 15 行的零件清单上,因此是 15-1、15-2 等。我仍然希望将它作为项目 1、2 和 3 保存在数据库中,但显示为其他内容视情况而定。
    • 正确,完全正确。将您的问题域与持久性域分开。您不想修改零件中的信息,因为绘图是如何使用它的,特别是因为每张绘图都会以不同的方式使用它。查看一些围绕这个概念的设计模式。我不想逃跑并开始建议,但绝对不要因此而改变实体。
    【解决方案2】:

    【讨论】:

    • detached 顶级对象,但它仍然保留较低级别的对象。如果我detach 是较低级别的对象,那么我会得到一个 PersistentObjectException: detached entity pass to persist。有什么想法吗?
    • 如果我调用任何存储库,即使存储库与分离实体无关,我似乎也会收到分离实体异常。这是意料之中的吗,有没有办法解决这个问题?
    • spring-data-jpa 为每个存储库使用单独的实体管理器,它自己管理连接,因此尝试使用 spring-data-jpa 使 JPA 变得复杂将是一个挫折的练习。您应该决定是要使用 JPA 还是 spring-data-jpa,并将您的想法集中在其中一个上。
    • @K.Nicholas 我并没有真正关注你。专注于其中之一的方法是什么?
    • 顶级和低级我假设你是指父母和孩子?还是继承?由于您假设我们知道您的代码,因此不清楚您的问题是什么。简而言之,spring-data-jpa 不是 jpa。它是 jpa 之上的一个抽象层。我是说在尝试错误地使用 spring-data-jpa 之前,您需要先了解这一点。其次,我认为更重要的是,请参阅下面的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    • 2019-06-15
    • 1970-01-01
    • 2019-02-09
    • 2019-12-21
    相关资源
    最近更新 更多