checks for constraint violation before persisting an entity

耗尽温柔 提交于 2019-11-30 11:28:07

Even if you check the condition in your code before persisting the user object there is always a chance that someone will created a duplicate loginid between the time you check and when you persist the new User.

However it'll be easier to display an appropriate error message in the UI if you do an explicit check. If you have multiple contraints on the table catching the ConstraintViolationException won't allow you to easily determine which constraint has been violated.

So I would do both. Assuming you're extending from Seam's EntityHome:

  1. In the persist() method run a query to ensure that the loginid is unique. If it isn't add an error message to the appropriate control and return null.
  2. Wrap the call to super.persist() and catch the ConstraintViolationException, displaying a generic duplicate error message

EDIT

As Shervin mentioned creating a JSF Validator is a great idea (replacing) #1 above, but you should still expect the worst and catch ConstraintViolationException.

I disagree with handling ConstraintException. I have written a validator that checks duplicates before saving, and it works great.

Here is an example checking duplicate emails.

@Name("emailValidator")
@Validator
@BypassInterceptors
@Transactional
public class UniqueEmailValidator implements javax.faces.validator.Validator, Serializable {

private static final long serialVersionUID = 6086372792387091314L;

@SuppressWarnings("unchecked")
public void validate(FacesContext facesContext, UIComponent component, Object value) throws ValidatorException {
    EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
    String newEmail = (String) value;
    String oldEmail = String.valueOf(component.getAttributes().get("oldEmail"));
    if (oldEmail != null && !oldEmail.equalsIgnoreCase(newEmail)) {
        List<User> users = entityManager.createQuery(
                "SELECT DISTINCT u FROM " + User.class.getName() + " p where lower(p.fromEmail) = :email").setParameter("email",
                newEmail.toLowerCase()).getResultList();
        if (!users.isEmpty()) {
            Map<String, String> messages = Messages.instance();
            throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, messages.get("admin.emailexists"), messages
                    .get("admin.emailexists")));
        }
    }
}
}

And in your form (xhtml) you write:

<s:decorate template="/layout/definition.xhtml">
        <ui:define name="label">#{messages['processdata.email']}</ui:define>
        <h:inputText id="fromEmail" size="30" required="true" value="#  {userAdmin.existingUser.fromEmail}">
            <f:validator validatorId="emailValidator"/>
            <f:attribute name="oldEmail" value="#{userAdmin.existingUser.fromEmail}" />
            <s:validate />
        </h:inputText>
    </s:decorate>

This way it will always validate the field before saving. You can even put an a:support tag to validate when focus is changed.

My advice is that if you can check a condition then check it i.e. in your case a UserExists method call. Throwing exceptions is expensive and is intended for exceptional cases normally related to things outwith your control e.g. disc access etc

You would generally perform this check in your business logic before calling for the entity to be added to the database.

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