我有一个简单的Play应用程序用于测试。我有2个控制器,一个是显示条目列表的“ListController”。每个条目都有一个“编辑”链接,转到“EditController”。 “EditController”将html表单与条目的现有数据一起显示,并且“提交”按钮将该数据发布到“EditController”中的另一个方法,该方法将数据保存到db并重新显示表单中新修改的数据。这一切都运转正常。但是,当我在返回列表时修改一个条目(在编辑页面中正确地重新显示)时,该条目仍然具有旧值,并且编辑它仍然使用旧值显示它。这在测试和开发环境中都会发生。
这是我的设置:
@OnApplicationStart
带注释的BootStrap类配置的测试环境:
%test.db的= FS
%test.jpa.ddl =创建
分贝= postgres的:// postgres的:postgre @本地:5432 /播放
ListController:
列出LaundryLists = LaundryList.findAll();
-EditController
LaundryList updatedLaundryList = LaundryList.em().merge(laundryList);
我已经添加了日志输出,当然,在调用EditController中的merge
方法之后,即使我添加代码以从数据库中检索更新的实体,它也会返回一个具有正确更新值的bean,例如我如何插入它们
然而,即使在此之后,在我重新键入(或单击链接)ListCOntroller时,在测试(播放测试)或运行(播放运行)环境中,它仍然显示具有其具有的值的(据称)修改的条目在EditController中发生更新之前。如果我再次点击进行编辑,表单会向我显示该条目的初始未修改数据。
我的问题是,我应该怎么做才能将数据保存到数据库?
答案 0 :(得分:6)
我找到了解决方案,但这非常令人失望。
简而言之,我所做的就是替换这一行:
LaundryList.em()合并(laundryList);
用这个:
LaundryList updateLaundryList = LaundryList.em().merge(laundryList);
updateLaundryList.save();
答案很长:Play改变了JPA实际工作的方式。在上面的例子中,我处于一个事务中(日志清楚地显示了这一事实,如果我尝试启动事务,则会引发一个异常,告诉我我实际上已经处于已经运行的事务中)。但是,即便如此,执行em().merge
实际上并没有对数据库执行任何插入/更新,如日志中所示。
是的,在他们网站的某个时刻,他们会说“我们不喜欢JPA在您进行交易时自动同步数据,因此您不需要调用persist / merge,但你确实需要调用刷新你想要撤消你的更改,我们不喜欢这样,所以我们改掉了它:现在你必须明确保存,否则什么都不会更新“。
他们也说(在这里我找到了实际的报价):
“在连续请求期间,使用对象ID从数据库中检索对象,更新它,然后再次保存。”
但就是这样。没有代码示例也没有。因为他们改变了比Play更为人所知的框架(即JPA)的行为,所以他们应该更清楚地指明这一点,或者至少改变类名,制作包装器,说他们自己制作PlayPersistenceManager或者其他东西
不,不,我个人不认为他们的方式更好。总的来说,你很可能坚持/更新某些东西而不是撤消一些变化,所以如果持久化/更新自动发生(没有样板代码)并且你需要明确地进行撤销,那就更好了。 p>