我有一个简单的Play应用程序进行测试。我有2个控制器,一个是“ListController”,它显示条目列表。每个条目都有一个“编辑”链接,该链接转到“EditController”。 “EditController”将html表单与该条目的现有数据一起显示,并且Submit按钮将该数据发布到“EditController”中的另一个方法,该方法将数据保存到db并在表单中重新显示新修改的数据。所有这些都可以。但是,一旦我修改了一个条目(在编辑页面中正确显示了该条目),当我返回列表时,该条目仍然具有旧值,并且对其进行编辑仍会显示旧值。在测试和开发环境中都会发生这种情况。

这是我的设置:

  • 通过带注释的BootStrap类
  • @OnApplicationStart初始化data.yml文件中的数据
  • 测试环境配置为:

    %test.db = fs

    %test.jpa.ddl =创建
  • dev环境配置为:

  • db = postgres:// postgres:postgre @ localhost:5432 / play
  • ListController:

    列出洗衣清单= LaundryList.findAll();

  • -EditController
    LaundryList updatedLaundryList = LaundryList.em().merge(laundryList);
    

    我已经添加了日志输出,并且肯定地,在EditController中调用merge方法之后,即使我添加了从数据库中检索更新的实体的代码,它也会返回具有正确更新值的Bean,例如我如何插入它们

    但是,即使在此之后,在我重新输入(或单击链接)ListCOntroller的测试(播放测试)或运行(播放运行)环境中,它仍然显示(据说)已修改的条目,其值与更新之前相同发生在EditController中。如果我再次单击以对其进行编辑,则该表单将向我显示该条目的从未修改过的初始数据。

    我的问题是,我应该怎么做才能将数据持久保存到数据库中?

    最佳答案

    我找到了解决方案,但这非常令人失望。

    简而言之,我所做的就是替换此行:

    LaundryList.em()。merge(laundryList);

    有了这个:

    LaundryList updateLaundryList = LaundryList.em().merge(laundryList);
    updateLaundryList.save();
    

    长答案是:播放更改了JPA的实际工作方式。在上述情况下,我正在事务中(日志清楚地表明了这一事实,并且如果我尝试启动事务,则会引发异常,告诉我实际上我已经在运行事务了)。但是,即使如此,执行em().merge实际上也不会对数据库进行任何插入/更新,如日志中所示。

    是的,在他们网站上的某个时刻,他们确实说了一些话:“我们不喜欢在进行事务处理时JPA如何自动同步数据,因此您不需要调用持久/合并,但是您确实实际上需要调用刷新来撤消您的更改,我们不喜欢这样做,所以我们撤消了它:现在您必须显式保存,否则什么也不会更新。”

    他们还说(在这里我找到了实际的报价):

    “在连续的请求期间,使用对象ID从数据库中检索对象,对其进行更新,然后再次保存。”

    就是这样。没有代码示例就没有。由于他们改变了一个比Play更广为人知的框架(即JPA)的行为,因此,他们应该更清楚地指定它,或者至少更改类名,进行包装,说他们做了自己的PlayPersistenceManager或其他东西。 。

    不,我个人认为他们的方法没有更好的选择。总体而言,您保留/更新某些内容的可能性要比撤消某些更改的可能性更大,因此,如果保留/更新自动发生(没有样板代码)并且您需要明确执行撤消操作,则更好。

    08-04 16:22