BeanEditForm onValidate()

classic Classic list List threaded Threaded
15 messages Options
Reply | Threaded
Open this post in threaded view
|

BeanEditForm onValidate()

Christopher
Hi there,

Below is my onValidate() method of a BeanEditForm for updating a user's
profile, where I simply check that a user isn't changing his username to
an already taken username.  The error output (below it) suggests that
BeanEditForm is committing the change to the database even before
onValidate() is called - certainly not what I wish to occur.

Could someone please explain what is happening here, as it runs contrary
to my understanding of form validation.  Thanks very much for your help.


======================================================================
            FORM VALIDATION METHOD
======================================================================

/**
 * Do the cross-field validation
 * Record any error, and thereby prevent Tapestry from emitting a
"success" event
 */
@Log
public void onValidateFromUpdateForm(){
        LOG.debug("onValidateFromUpdateForm");

    LOG.debug("Form user: [" + user.getUserName() + "|" +
user.getFirstName() + "|" + user.getLastName() + "]");  //For
debugging only (delete)

    //Validate user name (remains unique)
    User userVerif =
crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
QueryParameters.with("userName", user.getUserName()).parameters());

    LOG.debug("Verify user: [" + userVerif.getUserName() + "|" +
userVerif.getFirstName() + "|" + userVerif.getLastName() + "]");
//For debugging only (delete)

    if(!userVerif.equals(user)){
        //User name already taken by someone else
        updateForm.recordError(messages.get("error.userNameTaken"));
    }
}


======================================================================
            LOG OUTPUT
======================================================================

13-01-2018 00:28:09 DEBUG UpdateUser:74 - [ENTER] onValidateFromUpdateForm()
13-01-2018 00:28:09 DEBUG UpdateUser:177 - onValidateFromUpdateForm
13-01-2018 00:28:09 DEBUG UpdateUser:179 - Form user: [Kimmy|James|Cook]
13-01-2018 00:28:09 WARN  SqlExceptionHelper:145 - SQL Error: 1062,
SQLState: 23000
13-01-2018 00:28:09 ERROR SqlExceptionHelper:147 - Duplicate entry 'Kimmy'
for key 'UK_h029unq4qgmbvesub83df4vok'
13-01-2018 00:28:09 DEBUG UpdateUser:165 - [ FAIL]
onValidateFromUpdateForm --
org.hibernate.exception.ConstraintViolationException
org.hibernate.exception.ConstraintViolationException: could not execute
statement
...
Caused by: java.sql.SQLIntegrityConstraintViolationException: Duplicate
entry 'Kimmy' for key 'UK_h029unq4qgmbvesub83df4vok'
...
13-01-2018 00:28:09 ERROR Registry:208 - could not execute statement
13-01-2018 00:28:09 ERROR Registry:209 - Operations trace:
13-01-2018 00:28:09 ERROR Registry:218 - [ 1] Handling traditional
'action' component event request for user/Update:updateform.form.
13-01-2018 00:28:09 ERROR Registry:218 - [ 2] Triggering event 'action' on
user/Update:updateform.form
13-01-2018 00:28:09 ERROR Registry:218 - [ 3] Triggering event 'validate'
on user/Update:updateform.form
13-01-2018 00:28:09 ERROR RequestExceptionHandler:236 - Processing of
request failed with uncaught exception:
org.apache.tapestry5.runtime.ComponentEventException: could not execute
statement [at classpath:com/optomus/harbour/components/OptoEditForm.tml,
line 2]
org.apache.tapestry5.runtime.ComponentEventException: could not execute
statement [at classpath:com/optomus/harbour/components/OptoEditForm.tml,
line 2]
...
Caused by: org.apache.tapestry5.ioc.internal.OperationException: could not
execute statement [at
classpath:com/optomus/harbour/components/OptoEditForm.tml, line 2]
...
Caused by: org.apache.tapestry5.runtime.ComponentEventException: could not
execute statement [at
classpath:com/optomus/harbour/components/OptoEditForm.tml, line 2]
...
Caused by: org.hibernate.exception.ConstraintViolationException: could not
execute statement
...
Caused by: java.sql.SQLIntegrityConstraintViolationException: Duplicate
entry 'Kimmy' for key 'UK_h029unq4qgmbvesub83df4vok'
...



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

"A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry.
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

bobharner
Does the userVerif.equals(user) clause actually result in true? If not,
then recordError wouldn't run, and validation would be considered to have
passed. Check User.java's equals method, or better yet, maybe just compare
the username strings directly.

On Jan 12, 2018 7:04 AM, "Christopher Dodunski" <ChrisFromTapestry@
christopher.net.nz> wrote:

> Hi there,
>
> Below is my onValidate() method of a BeanEditForm for updating a user's
> profile, where I simply check that a user isn't changing his username to
> an already taken username.  The error output (below it) suggests that
> BeanEditForm is committing the change to the database even before
> onValidate() is called - certainly not what I wish to occur.
>
> Could someone please explain what is happening here, as it runs contrary
> to my understanding of form validation.  Thanks very much for your help.
>
>
> ======================================================================
>             FORM VALIDATION METHOD
> ======================================================================
>
> /**
>  * Do the cross-field validation
>  * Record any error, and thereby prevent Tapestry from emitting a
> "success" event
>  */
> @Log
> public void onValidateFromUpdateForm(){
>         LOG.debug("onValidateFromUpdateForm");
>
>     LOG.debug("Form user: [" + user.getUserName() + "|" +
> user.getFirstName() + "|" + user.getLastName() + "]");  //For
> debugging only (delete)
>
>     //Validate user name (remains unique)
>     User userVerif =
> crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
> QueryParameters.with("userName", user.getUserName()).parameters());
>
>     LOG.debug("Verify user: [" + userVerif.getUserName() + "|" +
> userVerif.getFirstName() + "|" + userVerif.getLastName() + "]");
> //For debugging only (delete)
>
>     if(!userVerif.equals(user)){
>         //User name already taken by someone else
>         updateForm.recordError(messages.get("error.userNameTaken"));
>     }
> }
>
>
> ======================================================================
>             LOG OUTPUT
> ======================================================================
>
> 13-01-2018 00:28:09 DEBUG UpdateUser:74 - [ENTER]
> onValidateFromUpdateForm()
> 13-01-2018 00:28:09 DEBUG UpdateUser:177 - onValidateFromUpdateForm
> 13-01-2018 00:28:09 DEBUG UpdateUser:179 - Form user: [Kimmy|James|Cook]
> 13-01-2018 00:28:09 WARN  SqlExceptionHelper:145 - SQL Error: 1062,
> SQLState: 23000
> 13-01-2018 00:28:09 ERROR SqlExceptionHelper:147 - Duplicate entry 'Kimmy'
> for key 'UK_h029unq4qgmbvesub83df4vok'
> 13-01-2018 00:28:09 DEBUG UpdateUser:165 - [ FAIL]
> onValidateFromUpdateForm --
> org.hibernate.exception.ConstraintViolationException
> org.hibernate.exception.ConstraintViolationException: could not execute
> statement
> ...
> Caused by: java.sql.SQLIntegrityConstraintViolationException: Duplicate
> entry 'Kimmy' for key 'UK_h029unq4qgmbvesub83df4vok'
> ...
> 13-01-2018 00:28:09 ERROR Registry:208 - could not execute statement
> 13-01-2018 00:28:09 ERROR Registry:209 - Operations trace:
> 13-01-2018 00:28:09 ERROR Registry:218 - [ 1] Handling traditional
> 'action' component event request for user/Update:updateform.form.
> 13-01-2018 00:28:09 ERROR Registry:218 - [ 2] Triggering event 'action' on
> user/Update:updateform.form
> 13-01-2018 00:28:09 ERROR Registry:218 - [ 3] Triggering event 'validate'
> on user/Update:updateform.form
> 13-01-2018 00:28:09 ERROR RequestExceptionHandler:236 - Processing of
> request failed with uncaught exception:
> org.apache.tapestry5.runtime.ComponentEventException: could not execute
> statement [at classpath:com/optomus/harbour/components/OptoEditForm.tml,
> line 2]
> org.apache.tapestry5.runtime.ComponentEventException: could not execute
> statement [at classpath:com/optomus/harbour/components/OptoEditForm.tml,
> line 2]
> ...
> Caused by: org.apache.tapestry5.ioc.internal.OperationException: could not
> execute statement [at
> classpath:com/optomus/harbour/components/OptoEditForm.tml, line 2]
> ...
> Caused by: org.apache.tapestry5.runtime.ComponentEventException: could not
> execute statement [at
> classpath:com/optomus/harbour/components/OptoEditForm.tml, line 2]
> ...
> Caused by: org.hibernate.exception.ConstraintViolationException: could not
> execute statement
> ...
> Caused by: java.sql.SQLIntegrityConstraintViolationException: Duplicate
> entry 'Kimmy' for key 'UK_h029unq4qgmbvesub83df4vok'
> ...
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

Christopher
In reply to this post by Christopher
The database contains these two users:

User name: Abel
First name: Abel
Last name: Tasman
etc.

User name: James
First name: James
Last name: Cook
etc.

As a test I load user 'James' into the BeanEditForm of UpdateUser.java,
and attempt to change his user name to 'Abel' (an illegal change).  This
page's onValidate method attempts to instantiate a user 'userVerif' using
the new user name entered into the form: 'Abel'.  If instantiating
userVerif is successful (someone has this user name), and userVerif is a
different user (if both users are the same it simply means the form was
submitted without an altered user name field), it means that this user
name is already taken, so onValidate() records an error.

If no error is recorded, onSuccess() is then fired, and this is where the
updated user is finally committed to database:
"crudServiceDAO.update(user)".  At least this is my intention.

What actually happens in the above test scenario is that the user object
loaded into the BeanEditForm, on hitting the submit button, becomes...

User name: Abel
First name: James
Last name: Cook

So far so good, because this is still within onValidate(), not onSuccess()
where the user instance is committed using "crudServiceDAO.update(user)".
But seemingly when the line...

User userVerif = crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
QueryParameters.with("userName", user.getUserName()).parameters());

is reached, the exception below occurs...

13-01-2018 20:57:10 DEBUG UpdateUser:74 - [ENTER] onValidateFromUpdateForm()
13-01-2018 20:57:10 DEBUG UpdateUser:177 - onValidateFromUpdateForm
13-01-2018 20:57:10 DEBUG UpdateUser:179 - Form user: [Abel|James|Cook]
13-01-2018 20:57:11 WARN  SqlExceptionHelper:145 - SQL Error: 1062,
SQLState: 23000
13-01-2018 20:57:11 ERROR SqlExceptionHelper:147 - Duplicate entry 'Abel'
for key 'UK_h029unq4qgmbvesub83df4vok'
13-01-2018 20:57:11 DEBUG UpdateUser:165 - [ FAIL]
onValidateFromUpdateForm --
org.hibernate.exception.ConstraintViolationException
org.hibernate.exception.ConstraintViolationException: could not execute
statement

I'm confused by the "Duplicate entry 'Abel'" exception, as at this stage
there ought only be one 'Abel' in the database.

If onSuccess() attempted "crudServiceDAO.update(user)" with a user also
having userName=Abel, then naturally I would be expecting to see this
exception error.  But this is not the case.

Regards,

Chris.


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

"A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry.
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

bobharner
I don't think k you actually answered my question about the equals method
(or perhaps I misunderstood you). I'll try again:

1. Is the line with the recortError() method call actually being reached?
Use a debug breakpoint or log statement to prove it.
2. If not, have you overridden the equals method appropriately? (For
Hibernate entities it is officially recommended not to rely on the PK ID in
your equals and hashmap methods but instead base them on the closest thing
to a natural key or keys in each entity.)
3. Since you are just trying to ensure that a user isn't trying to reuse an
existing user name, why not directly compare the user name strings instead
of comparing the User objects?


On Jan 13, 2018 4:01 AM, "Christopher Dodunski" <
[hidden email]> wrote:

The database contains these two users:

User name: Abel
First name: Abel
Last name: Tasman
etc.

User name: James
First name: James
Last name: Cook
etc.

As a test I load user 'James' into the BeanEditForm of UpdateUser.java,
and attempt to change his user name to 'Abel' (an illegal change).  This
page's onValidate method attempts to instantiate a user 'userVerif' using
the new user name entered into the form: 'Abel'.  If instantiating
userVerif is successful (someone has this user name), and userVerif is a
different user (if both users are the same it simply means the form was
submitted without an altered user name field), it means that this user
name is already taken, so onValidate() records an error.

If no error is recorded, onSuccess() is then fired, and this is where the
updated user is finally committed to database:
"crudServiceDAO.update(user)".  At least this is my intention.

What actually happens in the above test scenario is that the user object
loaded into the BeanEditForm, on hitting the submit button, becomes...

User name: Abel
First name: James
Last name: Cook

So far so good, because this is still within onValidate(), not onSuccess()
where the user instance is committed using "crudServiceDAO.update(user)".
But seemingly when the line...

User userVerif = crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
QueryParameters.with("userName", user.getUserName()).parameters());

is reached, the exception below occurs...

13-01-2018 20:57:10 DEBUG UpdateUser:74 - [ENTER] onValidateFromUpdateForm()
13-01-2018 20:57:10 DEBUG UpdateUser:177 - onValidateFromUpdateForm
13-01-2018 20:57:10 DEBUG UpdateUser:179 - Form user: [Abel|James|Cook]
13-01-2018 20:57:11 WARN  SqlExceptionHelper:145 - SQL Error: 1062,
SQLState: 23000
13-01-2018 20:57:11 ERROR SqlExceptionHelper:147 - Duplicate entry 'Abel'
for key 'UK_h029unq4qgmbvesub83df4vok'
13-01-2018 20:57:11 DEBUG UpdateUser:165 - [ FAIL]
onValidateFromUpdateForm --
org.hibernate.exception.ConstraintViolationException
org.hibernate.exception.ConstraintViolationException: could not execute
statement

I'm confused by the "Duplicate entry 'Abel'" exception, as at this stage
there ought only be one 'Abel' in the database.

If onSuccess() attempted "crudServiceDAO.update(user)" with a user also
having userName=Abel, then naturally I would be expecting to see this
exception error.  But this is not the case.

Regards,

Chris.


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

Christopher
In reply to this post by Christopher
Hi Bob,

Evidently, equals is not being reached as there is no output in the logs
from the line containing "LOG.debug("Verify user...)".  The log file does
contain the output from "LOG.debug("Form user...)", two lines above.

So my focus has turned to the line containing "User userVerif =
crudServiceDAO.findUniqueWithNamedQuery...".

As a second test, I changed the user name of James to a name not already
taken: Charlie.  No exception is thrown, but recorded in the log file is
the output of "LOG.debug("Verify user...)", namely: Verify user:
[Charlie|James|Cook].

crudServiceDAO should be returning no user by this user name, as we are at
this stage still inside onValidateFromUpdateForm.

All quite puzzling.  :-)

Regards,

Chris.


> I don't think k you actually answered my question about the equals method
> (or perhaps I misunderstood you). I'll try again:
>
> 1. Is the line with the recortError() method call actually being reached?
> Use a debug breakpoint or log statement to prove it.
> 2. If not, have you overridden the equals method appropriately? (For
> Hibernate entities it is officially recommended not to rely on the PK ID
> in
> your equals and hashmap methods but instead base them on the closest thing
> to a natural key or keys in each entity.)
> 3. Since you are just trying to ensure that a user isn't trying to reuse
> an
> existing user name, why not directly compare the user name strings instead
> of comparing the User objects?
>
>
> On Jan 13, 2018 4:01 AM, "Christopher Dodunski" <
> [hidden email]> wrote:
>
> The database contains these two users:
>
> User name: Abel
> First name: Abel
> Last name: Tasman
> etc.
>
> User name: James
> First name: James
> Last name: Cook
> etc.
>
> As a test I load user 'James' into the BeanEditForm of UpdateUser.java,
> and attempt to change his user name to 'Abel' (an illegal change).  This
> page's onValidate method attempts to instantiate a user 'userVerif' using
> the new user name entered into the form: 'Abel'.  If instantiating
> userVerif is successful (someone has this user name), and userVerif is a
> different user (if both users are the same it simply means the form was
> submitted without an altered user name field), it means that this user
> name is already taken, so onValidate() records an error.
>
> If no error is recorded, onSuccess() is then fired, and this is where the
> updated user is finally committed to database:
> "crudServiceDAO.update(user)".  At least this is my intention.
>
> What actually happens in the above test scenario is that the user object
> loaded into the BeanEditForm, on hitting the submit button, becomes...
>
> User name: Abel
> First name: James
> Last name: Cook
>
> So far so good, because this is still within onValidate(), not onSuccess()
> where the user instance is committed using "crudServiceDAO.update(user)".
> But seemingly when the line...
>
> User userVerif = crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
> QueryParameters.with("userName", user.getUserName()).parameters());
>
> is reached, the exception below occurs...
>
> 13-01-2018 20:57:10 DEBUG UpdateUser:74 - [ENTER]
> onValidateFromUpdateForm()
> 13-01-2018 20:57:10 DEBUG UpdateUser:177 - onValidateFromUpdateForm
> 13-01-2018 20:57:10 DEBUG UpdateUser:179 - Form user: [Abel|James|Cook]
> 13-01-2018 20:57:11 WARN  SqlExceptionHelper:145 - SQL Error: 1062,
> SQLState: 23000
> 13-01-2018 20:57:11 ERROR SqlExceptionHelper:147 - Duplicate entry 'Abel'
> for key 'UK_h029unq4qgmbvesub83df4vok'
> 13-01-2018 20:57:11 DEBUG UpdateUser:165 - [ FAIL]
> onValidateFromUpdateForm --
> org.hibernate.exception.ConstraintViolationException
> org.hibernate.exception.ConstraintViolationException: could not execute
> statement
>
> I'm confused by the "Duplicate entry 'Abel'" exception, as at this stage
> there ought only be one 'Abel' in the database.
>
> If onSuccess() attempted "crudServiceDAO.update(user)" with a user also
> having userName=Abel, then naturally I would be expecting to see this
> exception error.  But this is not the case.
>
> Regards,
>
> Chris.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>



---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

"A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry.
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

JumpStart
In reply to this post by bobharner
I’m guessing that if you run that query earlier, for that user, then it would return the same exception. Try putting it in onActivate and pass it 'Abel'.

Is the query joining entities? Possibly it’s returning a cartesian product of the user with another entity, ie. more than one entity returned. With some types of query you need to squash out duplicate entries. It’s pretty hard to help more, though, without seeing the code for the query and the code for the entity or entities.

Geoff

> On 14 Jan 2018, at 12:23 am, Bob Harner <[hidden email]> wrote:
>
> I don't think k you actually answered my question about the equals method
> (or perhaps I misunderstood you). I'll try again:
>
> 1. Is the line with the recortError() method call actually being reached?
> Use a debug breakpoint or log statement to prove it.
> 2. If not, have you overridden the equals method appropriately? (For
> Hibernate entities it is officially recommended not to rely on the PK ID in
> your equals and hashmap methods but instead base them on the closest thing
> to a natural key or keys in each entity.)
> 3. Since you are just trying to ensure that a user isn't trying to reuse an
> existing user name, why not directly compare the user name strings instead
> of comparing the User objects?
>
>
> On Jan 13, 2018 4:01 AM, "Christopher Dodunski" <
> [hidden email]> wrote:
>
> The database contains these two users:
>
> User name: Abel
> First name: Abel
> Last name: Tasman
> etc.
>
> User name: James
> First name: James
> Last name: Cook
> etc.
>
> As a test I load user 'James' into the BeanEditForm of UpdateUser.java,
> and attempt to change his user name to 'Abel' (an illegal change).  This
> page's onValidate method attempts to instantiate a user 'userVerif' using
> the new user name entered into the form: 'Abel'.  If instantiating
> userVerif is successful (someone has this user name), and userVerif is a
> different user (if both users are the same it simply means the form was
> submitted without an altered user name field), it means that this user
> name is already taken, so onValidate() records an error.
>
> If no error is recorded, onSuccess() is then fired, and this is where the
> updated user is finally committed to database:
> "crudServiceDAO.update(user)".  At least this is my intention.
>
> What actually happens in the above test scenario is that the user object
> loaded into the BeanEditForm, on hitting the submit button, becomes...
>
> User name: Abel
> First name: James
> Last name: Cook
>
> So far so good, because this is still within onValidate(), not onSuccess()
> where the user instance is committed using "crudServiceDAO.update(user)".
> But seemingly when the line...
>
> User userVerif = crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
> QueryParameters.with("userName", user.getUserName()).parameters());
>
> is reached, the exception below occurs...
>
> 13-01-2018 20:57:10 DEBUG UpdateUser:74 - [ENTER] onValidateFromUpdateForm()
> 13-01-2018 20:57:10 DEBUG UpdateUser:177 - onValidateFromUpdateForm
> 13-01-2018 20:57:10 DEBUG UpdateUser:179 - Form user: [Abel|James|Cook]
> 13-01-2018 20:57:11 WARN  SqlExceptionHelper:145 - SQL Error: 1062,
> SQLState: 23000
> 13-01-2018 20:57:11 ERROR SqlExceptionHelper:147 - Duplicate entry 'Abel'
> for key 'UK_h029unq4qgmbvesub83df4vok'
> 13-01-2018 20:57:11 DEBUG UpdateUser:165 - [ FAIL]
> onValidateFromUpdateForm --
> org.hibernate.exception.ConstraintViolationException
> org.hibernate.exception.ConstraintViolationException: could not execute
> statement
>
> I'm confused by the "Duplicate entry 'Abel'" exception, as at this stage
> there ought only be one 'Abel' in the database.
>
> If onSuccess() attempted "crudServiceDAO.update(user)" with a user also
> having userName=Abel, then naturally I would be expecting to see this
> exception error.  But this is not the case.
>
> Regards,
>
> Chris.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

Christopher
In reply to this post by Christopher
Below is a snippet of my User entity class, where the NamedQueries are
also located.

Based on your responses, it seems that I'm correct that UpdateUser.java
oughtn't be persisting anything for NamedQuery to discover until the line
"crudServiceDAO.update(user)" is reached in onSuccessFromUpdateForm().  In
other words, fault is with the query and not with BeanEditForm prematurely
saving the altered entity, yes?


==================================================
            User.java
==================================================

@Entity
@NamedQueries({
        @NamedQuery(name = User.ALL, query = "Select u from User u"),
        @NamedQuery(name = User.BY_USERNAME, query = "Select u from User u
where u.userName = :userName"),
        @NamedQuery(name = User.BY_EMAIL, query = "Select u from User u
where u.email = :email"),
        @NamedQuery(name = User.BY_USERNAME_OR_EMAIL, query = "Select u
from User u where u.userName = :userName or u.email = :email"),
        @NamedQuery(name = User.BY_CREDENTIALS, query = "Select u from
User u where u.userName = :userName and u.password = :password")
})
@Table(name="USER")
public class User {

    public static final String ALL = "User.all";
    public static final String BY_USERNAME = "User.byUserName";
    public static final String BY_EMAIL = "User.byEmail";
    public static final String BY_USERNAME_OR_EMAIL =
"User.byUserNameOrEmail";
    public static final String BY_CREDENTIALS = "User.byCredentials";
    private static final long serialVersionUID = 4060967693790504175L;

    @Id
    @NonVisual
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="USER_ID")
    private long id;

    //@NaturalId
    @Column(name="USER_NAME", nullable=false, unique=true, length=50)
    @Validate("required")
    @NotNull
    @Size(min = 4, max = 50)
    @Alphanumeric
    private String userName;


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

"A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry.
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

Christopher
In reply to this post by Christopher
To summarise...

the exceptions:

    org.hibernate.exception.ConstraintViolationException

    could not execute statement

    SQL
        n/a
    SQLState
        23000
    errorCode
        1062

and:

    java.sql.SQLIntegrityConstraintViolationException

    Duplicate entry 'Abel' for key 'UK_h029unq4qgmbvesub83df4vok'

    SQLState
        23000
    errorCode
        1062

is thrown when the below line is reached in onValidate():

    User userVerif =
crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
QueryParameters.with("userName", user.getUserName()).parameters());

yet this is only calling the below 'HQL select' NamedQuery:

    @NamedQuery(name = User.BY_USERNAME, query = "Select u from User u
where u.userName = :userName"),

which raises the question:

    Who or what is automatically attempting to illegally persist a user
with duplicate userName?  BeanEditForm?  Hibernate?  Ghosts?

Quoting from http://tapestry.apache.org/beaneditform-guide.html:

    Automatic Object Creation

    If the object does not exist, it will be created as needed.

Does altering the userName field (a unique field) invoke this "automatic
object creation"?  I don't imagine this is the case, else why would
BeanEditForm bother firing a 'validate' event?


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

"A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry.
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

JumpStart
Did you miss my suggestion?

        Try putting it in onActivate and pass it 'Abel'.

I’m hoping it will have the same problem, because, as you know, it makes no sense that a transaction has taken place before onValidate().

Longer term, however, you should scrap the validation because it can be subject to a race condition. Instead, in the database make username UNIQUE, and on insert or update it will fail if username is not unique. It’s easy enough to interpret the error to determine to was due to “alternate key not unique”.

> On 15 Jan 2018, at 7:21 pm, Christopher Dodunski <[hidden email]> wrote:
>
> To summarise...
>
> the exceptions:
>
>    org.hibernate.exception.ConstraintViolationException
>
>    could not execute statement
>
>    SQL
>        n/a
>    SQLState
>        23000
>    errorCode
>        1062
>
> and:
>
>    java.sql.SQLIntegrityConstraintViolationException
>
>    Duplicate entry 'Abel' for key 'UK_h029unq4qgmbvesub83df4vok'
>
>    SQLState
>        23000
>    errorCode
>        1062
>
> is thrown when the below line is reached in onValidate():
>
>    User userVerif =
> crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
> QueryParameters.with("userName", user.getUserName()).parameters());
>
> yet this is only calling the below 'HQL select' NamedQuery:
>
>    @NamedQuery(name = User.BY_USERNAME, query = "Select u from User u
> where u.userName = :userName"),
>
> which raises the question:
>
>    Who or what is automatically attempting to illegally persist a user
> with duplicate userName?  BeanEditForm?  Hibernate?  Ghosts?
>
> Quoting from http://tapestry.apache.org/beaneditform-guide.html:
>
>    Automatic Object Creation
>
>    If the object does not exist, it will be created as needed.
>
> Does altering the userName field (a unique field) invoke this "automatic
> object creation"?  I don't imagine this is the case, else why would
> BeanEditForm bother firing a 'validate' event?
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>

Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

Christopher
In reply to this post by Christopher
Hi Geoff,

Sorry, I'll try that when back at my PC tomorrow.

I could be mistaken, but does the 'column' annotation below not set the
USER_NAME column in the database as unique?  I assumed this is the reason
for the ConstraintViolationException, i.e. the unique field.

Irrespective, I'll do as you suggested in onActivate() and see what
results.  :-)

    //@NaturalId
    @Column(name="USER_NAME", nullable=false, unique=true, length=50)
    @Validate("required")
    @NotNull
    @Size(min = 4, max = 50)
    @Alphanumeric
    private String userName;


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

"A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry.
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

JumpStart
If Hibernate is creating/updating the database definition then you could be right. I’m not sure because I use this kind of thing for alternate key:

@Entity
@Table(name = "Users", uniqueConstraints = { @UniqueConstraint(columnNames = { “username" }) })
public class User ...


> On 16 Jan 2018, at 5:42 pm, Christopher Dodunski <[hidden email]> wrote:
>
> Hi Geoff,
>
> Sorry, I'll try that when back at my PC tomorrow.
>
> I could be mistaken, but does the 'column' annotation below not set the
> USER_NAME column in the database as unique?  I assumed this is the reason
> for the ConstraintViolationException, i.e. the unique field.
>
> Irrespective, I'll do as you suggested in onActivate() and see what
> results.  :-)
>
>    //@NaturalId
>    @Column(name="USER_NAME", nullable=false, unique=true, length=50)
>    @Validate("required")
>    @NotNull
>    @Size(min = 4, max = 50)
>    @Alphanumeric
>    private String userName;
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>

Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

Chris Poulsen
You could try setting a break point in the database update code and some in
the event handlers and the examine the call stack to see where the call
originates from and in which order things happen

--
Chris

On Tue, Jan 16, 2018 at 10:51 AM, JumpStart <
[hidden email]> wrote:

> If Hibernate is creating/updating the database definition then you could
> be right. I’m not sure because I use this kind of thing for alternate key:
>
> @Entity
> @Table(name = "Users", uniqueConstraints = { @UniqueConstraint(columnNames
> = { “username" }) })
> public class User ...
>
>
> > On 16 Jan 2018, at 5:42 pm, Christopher Dodunski <ChrisFromTapestry@
> christopher.net.nz> wrote:
> >
> > Hi Geoff,
> >
> > Sorry, I'll try that when back at my PC tomorrow.
> >
> > I could be mistaken, but does the 'column' annotation below not set the
> > USER_NAME column in the database as unique?  I assumed this is the reason
> > for the ConstraintViolationException, i.e. the unique field.
> >
> > Irrespective, I'll do as you suggested in onActivate() and see what
> > results.  :-)
> >
> >    //@NaturalId
> >    @Column(name="USER_NAME", nullable=false, unique=true, length=50)
> >    @Validate("required")
> >    @NotNull
> >    @Size(min = 4, max = 50)
> >    @Alphanumeric
> >    private String userName;
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [hidden email]
> > For additional commands, e-mail: [hidden email]
> >
>
>
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

Christopher
In reply to this post by Christopher
Hi Geoff,

I'm not sure whether this is what you meant, but I added the below code to
my onActivate() method:

        User userVerif =
crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
QueryParameters.with("userName",
user.getUserName()).parameters());
        LOG.debug("Verify user: [" + userVerif.getUserName() + "|" +
userVerif.getFirstName() + "|" + userVerif.getLastName() + "]");

Below is the log output.  There is no error loading the page.

17-01-2018 23:29:26 DEBUG UpdateUser:74 - [ENTER]
onActivate(<EventContext: Welcome, 3>)
17-01-2018 23:29:26 DEBUG UpdateUser:103 - onActivate
17-01-2018 23:29:26 INFO  UpdateUser:154 - User James [uid:3] was granted
access to the UpdateUser page to update: James [uid:3]
17-01-2018 23:29:26 DEBUG UpdateUser:158 - Verify user: [James|James|Cook]
17-01-2018 23:29:26 DEBUG UpdateUser:154 - [ EXIT] onActivate [null]


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

"A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry.
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

Christopher
And when using the literal "Abel", as below...

        User userVerif =
crudServiceDAO.findUniqueWithNamedQuery(User.BY_USERNAME,
QueryParameters.with("userName", "Abel").parameters());
        LOG.debug("Verify user: [" + userVerif.getUserName() + "|" +
userVerif.getFirstName() + "|" + userVerif.getLastName() + "]");

Again, no error.  Log output is:

17-01-2018 23:41:15 DEBUG UpdateUser:74 - [ENTER]
onActivate(<EventContext: Welcome, 3>)
17-01-2018 23:41:15 DEBUG UpdateUser:103 - onActivate
17-01-2018 23:41:15 INFO  UpdateUser:154 - User James [uid:3] was granted
access to the UpdateUser page to update: James [uid:3]
17-01-2018 23:41:15 DEBUG UpdateUser:158 - Verify user: [Abel|Abel|Tasman]
17-01-2018 23:41:15 DEBUG UpdateUser:154 - [ EXIT] onActivate [null]


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

"A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry.
Reply | Threaded
Open this post in threaded view
|

Re: BeanEditForm onValidate()

Christopher
Mystery solved!

My original suspicion was correct in that somewhere the app was attemting
to update the database before or while onValidate() was doing it's thing.

It wasn't BeanEditForm however, it was Hibernate jumping in the way.  Part
of the stack trace:

org.hibernate.event.internal.DefaultAutoFlushEventListener onAutoFlush()
DefaultAutoFlushEventListener.java 62
org.hibernate.internal.SessionImpl autoFlushIfRequired() SessionImpl.java
1205
org.hibernate.internal.SessionImpl list() SessionImpl.java 1262
org.hibernate.internal.QueryImpl list() QueryImpl.java 101
org.hibernate.internal.AbstractQueryImpl uniqueResult()
AbstractQueryImpl.java 905
com.optomus.harbour.dal.HibernateCrudServiceDAO findUniqueWithNamedQuery()
HibernateCrudServiceDAO.java 90

Hibernate has identified that there are uncommitted changes to one of the
bound model instances.  The auto flush is attempting to commit that to the
database.

The solution is to add "setFlushMode(FlushMode.MANUAL)" to my
findUniqueWithNamedQuery() method:

    public <T> T findUniqueWithNamedQuery(String queryName, Map<String,
Object> params)
    {
        Set<Entry<String, Object>> rawParameters = params.entrySet();
        Query query = session.getNamedQuery(queryName);

        for (Entry<String, Object> entry : rawParameters)
        {
            query.setParameter(entry.getKey(), entry.getValue());

        }
        return (T) query.setFlushMode(FlushMode.MANUAL).uniqueResult();
    }

This default Hibernate behaviour potentially interferes whenever
BeanEditForm is used to update a record.  It seems to catch many Hibernate
users out.  A valuable lesson learned that I shan't forget.  :-)

Thanks & regards,

Chris.


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

"A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away." - Antoine de Saint-Exupéry.