Play framework: merge action only works in the Controller that triggered it

一笑奈何 提交于 2020-01-04 01:37:06

问题


I have a simple Play applicaiton for test. I have 2 controllers, one is a "ListController" that displays a list of entries. Each entry has an "edit" link which goes to the "EditController". The "EditController" diplays the html form with the existing data for the entry, and the submit button posts that data towards another method in the "EditController", which saves the data to db and redisplays the newly modify data in the form. All this works ok. However once I modify an entry (which is redisplayed correctly in the edit page) when I return to the list, that entry still has the old values, and editing it still shows it with the old values. This happends both in test and dev environment.

Here's my setup:

  • initialize data from data.yml file, via @OnApplicationStart annotated BootStrap class
  • test environment configured with :

    %test.db=fs

    %test.jpa.ddl=create

  • dev environment configured with:

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

  • ListController:

    List laundryLists = LaundryList.findAll();

-EditController

LaundryList updatedLaundryList = LaundryList.em().merge(laundryList);

I've added log output and sure enough, after calling the merge method in the EditController, even if I add code to retrieve the updated entity from the database, it returns a bean with correctly updated values such as how I inserted them

However, even after this, in either test (play test) or run (play run) environmetns once I retype (or click the link) for the ListCOntroller, it still displays that (supposedly) modified entry with the values it had BEFORE the update happend in the EditController. And if I click to edit it again, the form shows me THAT initial-never-modified data for the entry.

My question is, what should I actually do to have the data persisted to the database?


回答1:


I found the solution but this is very disappointing.

In short, what I did is replace this line:

LaundryList.em().merge(laundryList);

with this:

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

The long answer is: Play changed the way JPA actually works. In the above case I was in a transaction (this was clearly shown by the logs and the fact that if I tried to start a transaction an exception would be raised telling me I'm in fact in an already running transaction). However, even so, doing a em().merge did not in fact do any inserts/updates towards the db, as show in the logs.

Yes, at some point on their site they do say something on the lines of "we don't like how JPA auto-synchronizez data when you're in a transaction so you don't need to call persist/merge, but you do need to call refresh of you infact want to undo your changes, and we don't like that, so we reversed it: now you have to save explicitly, or nothing gets updated".

They also say (and here I found the actual quote):

"During successive requests, retrieve the object from the database using the object ID, update it, and save it again."

But that's it. No code examples no nothing. Since they'd changed the behavior of a framework which is A LOT more known than Play (namely JPA), they should really specify this more clearly, or at least change the class names, make wrappers, say they made their own PlayPersistenceManager or something.

And no, personally I don't think their way is better. On the whole you are A LOT more likely to persist/update something than you are to undo some changes, so it's better if the persist/update happends automatically (with no boiler plate code) and you need to explicitlly do an undo.



来源:https://stackoverflow.com/questions/8142392/play-framework-merge-action-only-works-in-the-controller-that-triggered-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!