You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by C N Davies <cn...@xcogia.com> on 2016/01/05 06:23:18 UTC

Editing a JPA entity

I'm using an action to retrieve a list of entities and render these as a
list, the user can then select an edit button that calls an action that
retrieves the individual entity and renders the edit page. Once the user has
completed editing they hit the save button which calls the action that calls
the entity manager's merge method to update the db. Each of these actions
call methods of the same action class, but the entity ends up in a detached
state so merge will fail. I could just retrieve the entity again and then
update each data member but this seems like a very messy way to do it. Is
there a better way to do this with struts?

 

I'm using struts 2.3.20 with hibernate 4.3.11

 

 


Re: Editing a JPA entity

Posted by Ken McWilliams <ke...@gmail.com>.
Just my two cents, you can avoid the lookup by using a JPQL UPDATE query.
If used to update a single record you avoid the lookup. If versioning is an
issue this may not be ideal (still you could manually set the version),
also if you expect to reuse objects you lose the ability to proxy, if those
are not issues... there is no reason not to do this.

On Thu, Jan 7, 2016 at 4:26 PM, CRANFORD, CHRIS <Ch...@setech.com>
wrote:

> In the case of non-versioned domain models or cases where you aren't
> concerned with state collisions, the traditional lookup/render/lookup/merge
> workflow works quite well.
>
> The problem though comes into play when you are concerned about versioned
> models and more importantly, controlling state transition across concurrent
> modifications.  What I have seen developers do in the past is that they
> expose the @Version property to the form and have that value posted back
> along with the changed attributes during the save/update operation.  This
> approach works, but the security risk is you're exposing a critical piece
> of data that is subject to user manipulation to bypass optimistic locking.
>
> A better approach is to follow a similar paradigm that JSF uses called
> conversation scopes.  The struts2-conversation-plugin offers this kind of
> feature.
>
> The plugin basically allows you to expose a set of action properties to a
> named scope.  The plugin in combination with a few custom tags, allowed a
> form identifier to be placed as a hidden field in your form when you render
> your view.  When the view's changes are posted back to the save/update
> action, the plugin first takes the hidden field conversation id and looks
> up the state from the session that was saved when the conversation was
> started.  Any field flags to be included in the conversation will be
> rehydrated with the state it had when the prior action was executed.  The
> struts framework then can use it's normal property injection mechanism to
> set the appropriate state on the model.  Since the version of the domain
> model isn't being exposed to the client, there is no concern with a user
> hijacking the optimistic locking mechanism of your JPA provider to force
> changes  to occur when a collision should happen.
>
> A typical action might look like the following.  The annotations I show my
> now map exactly to the plugin as we use a modified proprietary version here
> but the gist remains the same.
>
> @ConversationSupport(conversation = "myconversion")
> public class SomeAction extends ActionSupport implements
> ModelDriven<ViewModel> {
>
>   private Long id;
>   @ConversationField private DomainModel domainModel;
>   @ConversationField private ViewModel viewModel;
>
>   @BeginConversation(conversation = "myconversion")
>   public String renderView() {
>     try {
>       this.domainModel = someService.find(id);
>       this.viewModel = new ViewModel(domainModel);
>       return SUCCESS;
>     }
>     catch(Exception ex) {
>       addActionError(getText(ERROR_UNEXPECTED_EXCEPTION));
>       return ERROR;
>     }
>   }
>
>   @Conversation(conversation = "myconversion")
>   public String saveView() {
>     try {
>       // copy values from this.viewModel to this.domainModel
>       someService.update(this.domainModel);
>       return SUCCESS;
>     }
>    catch(OptimisticLockException ex) {
>      // you could elect to find the domainModel again, update it and try
> to take
>      // the changes in domainModel + the changes from the user in viewModel
>      // and merge them then send the user back to the view again letting
> them
>      // know some fields were changed while they were making their changes.
>      // They can verify their changes again and resubmit.   I don't do
> this here
>      // but instead just tell the user the record was changed and they
> need to
>      // leave and come back in, but its up to you.
>      addActionError(getText(ERROR_RECORD_ALREADY_MODIFIED));
>      return INPUT;
>    }
>    catch(Exception ex) {
>      addActionError(getText(ERROR_UNEXPECTED_EXCEPTION));
>      return ERROR;
>    }
>   }
>
>   /* other stuffs */
>
> }
>
>
>
> -----Original Message-----
> From: C N Davies [mailto:cnd@xcogia.com]
> Sent: Wednesday, January 06, 2016 10:24 PM
> To: 'Christoph Nenning' <Ch...@lex-com.net>; 'Struts Users
> Mailing List' <us...@struts.apache.org>
> Subject: RE: Editing a JPA entity
>
> Christoph I understand why this happens, I was simply asking if there was
> a better way to do this using some struts session magic or such. Seems
> there isn't so I'll just do it the old long winded way.
>
>
> -----Original Message-----
> From: Christoph Nenning [mailto:Christoph.Nenning@lex-com.net]
> Sent: Tuesday, January 5, 2016 6:57 PM
> To: Struts Users Mailing List <us...@struts.apache.org>
> Subject: Re: Editing a JPA entity
>
> > I'm using an action to retrieve a list of entities and render these as
> > a list, the user can then select an edit button that calls an action
> > that retrieves the individual entity and renders the edit page. Once
> > the user
> has
> > completed editing they hit the save button which calls the action that
> calls
> > the entity manager's merge method to update the db. Each of these
> actions
> > call methods of the same action class, but the entity ends up in a
> detached
> > state so merge will fail. I could just retrieve the entity again and
> then
> > update each data member but this seems like a very messy way to do it.
> Is
> > there a better way to do this with struts?
> >
> >
> >
> > I'm using struts 2.3.20 with hibernate 4.3.11
> >
> >
>
>
> Well, that is basic http. When data is SELECTed from DB and the html page
> is rendered the server is done. That means at this point there are no more
> references to attached jpa objects. In terms of http: the handling of GET
> request is completed.
>
> When the user hits save the browser issues another http request, usually a
> POST request. On the server side there is no more state or information that
> there has been a GET request before and entities had been loaded.
>
> So yes, you have to retrieve the entity again and update it.
>
>
>
> Regards,
> Christoph
>
> This Email was scanned by Sophos Anti Virus
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
> For additional commands, e-mail: user-help@struts.apache.org
>
>
> Email secured by Check Point
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
> For additional commands, e-mail: user-help@struts.apache.org
>
>

RE: Editing a JPA entity

Posted by "CRANFORD, CHRIS" <Ch...@setech.com>.
In the case of non-versioned domain models or cases where you aren't concerned with state collisions, the traditional lookup/render/lookup/merge workflow works quite well.  

The problem though comes into play when you are concerned about versioned models and more importantly, controlling state transition across concurrent modifications.  What I have seen developers do in the past is that they expose the @Version property to the form and have that value posted back along with the changed attributes during the save/update operation.  This approach works, but the security risk is you're exposing a critical piece of data that is subject to user manipulation to bypass optimistic locking.  

A better approach is to follow a similar paradigm that JSF uses called conversation scopes.  The struts2-conversation-plugin offers this kind of feature.

The plugin basically allows you to expose a set of action properties to a named scope.  The plugin in combination with a few custom tags, allowed a form identifier to be placed as a hidden field in your form when you render your view.  When the view's changes are posted back to the save/update action, the plugin first takes the hidden field conversation id and looks up the state from the session that was saved when the conversation was started.  Any field flags to be included in the conversation will be rehydrated with the state it had when the prior action was executed.  The struts framework then can use it's normal property injection mechanism to set the appropriate state on the model.  Since the version of the domain model isn't being exposed to the client, there is no concern with a user hijacking the optimistic locking mechanism of your JPA provider to force changes  to occur when a collision should happen.

A typical action might look like the following.  The annotations I show my now map exactly to the plugin as we use a modified proprietary version here but the gist remains the same.

@ConversationSupport(conversation = "myconversion")
public class SomeAction extends ActionSupport implements ModelDriven<ViewModel> {

  private Long id;
  @ConversationField private DomainModel domainModel;
  @ConversationField private ViewModel viewModel;

  @BeginConversation(conversation = "myconversion")
  public String renderView() {
    try {
      this.domainModel = someService.find(id);
      this.viewModel = new ViewModel(domainModel);
      return SUCCESS;
    }
    catch(Exception ex) {
      addActionError(getText(ERROR_UNEXPECTED_EXCEPTION));
      return ERROR;
    }
  }

  @Conversation(conversation = "myconversion")
  public String saveView() {
    try {
      // copy values from this.viewModel to this.domainModel 
      someService.update(this.domainModel);
      return SUCCESS;
    }
   catch(OptimisticLockException ex) {
     // you could elect to find the domainModel again, update it and try to take 
     // the changes in domainModel + the changes from the user in viewModel
     // and merge them then send the user back to the view again letting them
     // know some fields were changed while they were making their changes.
     // They can verify their changes again and resubmit.   I don't do this here 
     // but instead just tell the user the record was changed and they need to 
     // leave and come back in, but its up to you.
     addActionError(getText(ERROR_RECORD_ALREADY_MODIFIED));
     return INPUT;
   }
   catch(Exception ex) {
     addActionError(getText(ERROR_UNEXPECTED_EXCEPTION));
     return ERROR;
   }
  }

  /* other stuffs */

}



-----Original Message-----
From: C N Davies [mailto:cnd@xcogia.com] 
Sent: Wednesday, January 06, 2016 10:24 PM
To: 'Christoph Nenning' <Ch...@lex-com.net>; 'Struts Users Mailing List' <us...@struts.apache.org>
Subject: RE: Editing a JPA entity

Christoph I understand why this happens, I was simply asking if there was a better way to do this using some struts session magic or such. Seems there isn't so I'll just do it the old long winded way.


-----Original Message-----
From: Christoph Nenning [mailto:Christoph.Nenning@lex-com.net]
Sent: Tuesday, January 5, 2016 6:57 PM
To: Struts Users Mailing List <us...@struts.apache.org>
Subject: Re: Editing a JPA entity

> I'm using an action to retrieve a list of entities and render these as 
> a list, the user can then select an edit button that calls an action 
> that retrieves the individual entity and renders the edit page. Once 
> the user
has
> completed editing they hit the save button which calls the action that
calls
> the entity manager's merge method to update the db. Each of these
actions
> call methods of the same action class, but the entity ends up in a
detached
> state so merge will fail. I could just retrieve the entity again and
then
> update each data member but this seems like a very messy way to do it. 
Is
> there a better way to do this with struts?
> 
> 
> 
> I'm using struts 2.3.20 with hibernate 4.3.11
> 
> 


Well, that is basic http. When data is SELECTed from DB and the html page is rendered the server is done. That means at this point there are no more references to attached jpa objects. In terms of http: the handling of GET request is completed.

When the user hits save the browser issues another http request, usually a POST request. On the server side there is no more state or information that there has been a GET request before and entities had been loaded.

So yes, you have to retrieve the entity again and update it.



Regards,
Christoph

This Email was scanned by Sophos Anti Virus


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org


Email secured by Check Point


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org


Re: Editing a JPA entity

Posted by Nick Broadhurst <ho...@gmail.com>.
Just to make sure - you are POSTing the object back to the action and THEN
merging the entity correct? Not just calling the merge function in the
action from the page? Sorry, I had to ask because it sort of sounds like
that is what you are saying. I am using Struts2 and JPA and I routinely
post objects (entities) to an action and use merge to update the entity.

On Thu, Jan 7, 2016 at 3:31 AM, Christoph Nenning <
Christoph.Nenning@lex-com.net> wrote:

> >
> > Christoph I understand why this happens, I was simply asking if there
> was a
> > better way to do this using some struts session magic or such. Seems
> there
> > isn't so I'll just do it the old long winded way.
> >
>
> If you want to store attached entities in session you can make your
> actions SessionAware:
> http://struts.apache.org/docs/http-session.html
>
> Of course that means you introduce state on your server which causes lots
> of problems.
>
>
> If you want to keep your app stateless struts can help you with loading
> and updating entities via the "paramsPrepareParamsStack".
>
> You can read a little about it here:
> http://struts.apache.org/docs/interceptors.html
>
>
>
> Regards,
> Christoph
>
>
>
> This Email was scanned by Sophos Anti Virus
>

RE: Editing a JPA entity

Posted by Christoph Nenning <Ch...@lex-com.net>.
> 
> Christoph I understand why this happens, I was simply asking if there 
was a
> better way to do this using some struts session magic or such. Seems 
there
> isn't so I'll just do it the old long winded way.
> 

If you want to store attached entities in session you can make your 
actions SessionAware:
http://struts.apache.org/docs/http-session.html

Of course that means you introduce state on your server which causes lots 
of problems.


If you want to keep your app stateless struts can help you with loading 
and updating entities via the "paramsPrepareParamsStack".

You can read a little about it here:
http://struts.apache.org/docs/interceptors.html



Regards,
Christoph



This Email was scanned by Sophos Anti Virus

RE: Editing a JPA entity

Posted by C N Davies <cn...@xcogia.com>.
Christoph I understand why this happens, I was simply asking if there was a
better way to do this using some struts session magic or such. Seems there
isn't so I'll just do it the old long winded way.


-----Original Message-----
From: Christoph Nenning [mailto:Christoph.Nenning@lex-com.net] 
Sent: Tuesday, January 5, 2016 6:57 PM
To: Struts Users Mailing List <us...@struts.apache.org>
Subject: Re: Editing a JPA entity

> I'm using an action to retrieve a list of entities and render these as 
> a list, the user can then select an edit button that calls an action 
> that retrieves the individual entity and renders the edit page. Once 
> the user
has
> completed editing they hit the save button which calls the action that
calls
> the entity manager's merge method to update the db. Each of these
actions
> call methods of the same action class, but the entity ends up in a
detached
> state so merge will fail. I could just retrieve the entity again and
then
> update each data member but this seems like a very messy way to do it. 
Is
> there a better way to do this with struts?
> 
> 
> 
> I'm using struts 2.3.20 with hibernate 4.3.11
> 
> 


Well, that is basic http. When data is SELECTed from DB and the html page is
rendered the server is done. That means at this point there are no more
references to attached jpa objects. In terms of http: the handling of GET
request is completed.

When the user hits save the browser issues another http request, usually a
POST request. On the server side there is no more state or information that
there has been a GET request before and entities had been loaded.

So yes, you have to retrieve the entity again and update it.



Regards,
Christoph

This Email was scanned by Sophos Anti Virus


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org


Re: Editing a JPA entity

Posted by Christoph Nenning <Ch...@lex-com.net>.
> I'm using an action to retrieve a list of entities and render these as a
> list, the user can then select an edit button that calls an action that
> retrieves the individual entity and renders the edit page. Once the user 
has
> completed editing they hit the save button which calls the action that 
calls
> the entity manager's merge method to update the db. Each of these 
actions
> call methods of the same action class, but the entity ends up in a 
detached
> state so merge will fail. I could just retrieve the entity again and 
then
> update each data member but this seems like a very messy way to do it. 
Is
> there a better way to do this with struts?
> 
> 
> 
> I'm using struts 2.3.20 with hibernate 4.3.11
> 
> 


Well, that is basic http. When data is SELECTed from DB and the html page 
is rendered the server is done. That means at this point there are no more 
references to attached jpa objects. In terms of http: the handling of GET 
request is completed.

When the user hits save the browser issues another http request, usually a 
POST request. On the server side there is no more state or information 
that there has been a GET request before and entities had been loaded.

So yes, you have to retrieve the entity again and update it.



Regards,
Christoph

This Email was scanned by Sophos Anti Virus