Play框架:合并操作仅适用于触发它的Controller

Shi*_*gon 3 java merge model playframework

我有一个简单的Play应用程序用于测试.我有2个控制器,一个是显示条目列表的"ListController".每个条目都有一个"编辑"链接,转到"EditController"."EditController"将html表单与条目的现有数据一起显示,并且"提交"按钮将该数据发布到"EditController"中的另一个方法,该方法将数据保存到db并重新显示表单中新修改的数据.这一切都运转正常.但是,当我在返回列表时修改一个条目(在编辑页面中正确地重新显示)时,该条目仍然具有旧值,并且编辑它仍然使用旧值显示它.这在测试和开发环境中都会发生.

这是我的设置:

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

    %test.db的= FS

    %test.jpa.ddl =创建

  • 开发环境配置:

DB = Postgres的:// Postgres的:postgre @本地:5432 /播放

  • ListController:

    清单LaundryLists = LaundryList.findAll();

-EditController

LaundryList updatedLaundryList = LaundryList.em().merge(laundryList);
Run Code Online (Sandbox Code Playgroud)

我已经添加了日志输出,当然,在mergeEditController中调用方法后,即使我添加代码从数据库中检索更新的实体,它也会返回一个bean,其中包含正确更新的值,例如我如何插入它们

但是,即使在此之后,在测试(播放测试)或运行(播放运行)环境中,一旦我为ListCOntroller重新键入(或单击链接),它仍然显示(据称)已修改的条目及其在更新之前的值发生在EditController中.如果我再次单击进行编辑,表单会向我显示该条目的初始未修改数据.

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

Shi*_*gon 6

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

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

.LaundryList.em()合并(laundryList);

有了这个:

LaundryList updateLaundryList = LaundryList.em().merge(laundryList);
updateLaundryList.save();
Run Code Online (Sandbox Code Playgroud)

答案很长:Play改变了JPA实际工作的方式.在上面的例子中,我处于一个事务中(日志清楚地显示了这一事实,如果我尝试启动事务,则会引发一个异常,告诉我我实际上已经处于已经运行的事务中).但是,即便如此,执行a em().merge实际上并没有对db进行任何插入/更新,如日志中所示.

是的,在他们网站的某个时刻,他们确实说了一句话:"我们不喜欢JPA在您进行交易时如何自动同步数据,因此您不需要调用persist/merge,但是你做了需要调用你的刷新实际上想要撤消你的更改,我们不喜欢这样,所以我们改变了它:现在你必须明确保存,否则什么都不会更新".

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

"在连续请求期间,使用对象ID从数据库中检索对象,更新它,然后再次保存."

但就是这样.没有代码示例也没有.由于他们改变了比Play更为人所知的框架(即JPA)的行为,他们应该更清楚地指定它,或者至少改变类名,制作包装器,说他们自己创建PlayPersistenceManager或者其他东西.

不,我个人不认为他们的方式更好.总的来说,你很可能坚持/更新某些东西而不是撤消一些变化,所以如果持久化/更新自动发生(没有样板代码)并且你需要明确地进行撤销,那就更好了.