在持久化实体之前检查约束违规

时间:2022-05-25 20:00:52

What is the best mechanism for preventing constraint violation checks before creation | modification of an entity?

在创建之前防止约束违规检查的最佳机制是什么?修改实体?

Suppose if the 'User' entity has 'loginid' as the unique constraint, would it be wise to check if there is an user entry already with this loginid name before creation or modification.

假设'User'实体将'loginid'作为唯一约束,在创建或修改之前检查是否已存在具有此loginid名称的用户条目是明智的。

OR

要么

Would you let the database throw an ConstraintViolationException and handle this message appropriately in the UI layer. Where should such checks be enforced in the jboss seam framework.

您是否允许数据库抛出ConstraintViolationException并在UI层中适当地处理此消息。应该在jboss seam框架中强制执行此类检查。

Note: Currently no such checks are enforced on the seam-gen code.

注意:目前没有对seam-gen代码强制执行此类检查。

We currently use Seam 2.2, Richfaces with Hibernate.

我们目前使用Seam 2.2,Richfaces和Hibernate。

3 个解决方案

#1


6  

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.

即使您在持久保存用户对象之前检查代码中的条件,也有可能有人在您检查的时间和持久保存新用户之间创建重复的loginid。

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.

但是,如果进行显式检查,在UI中显示相应的错误消息会更容易。如果表上有多个约束,捕获ConstraintViolationException将不允许您轻松确定违反了哪个约束。

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

所以我会两个都做。假设您从Seam的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. 在persist()方法中运行查询以确保loginid是唯一的。如果它没有向适当的控件添加错误消息并返回null。
  3. Wrap the call to super.persist() and catch the ConstraintViolationException, displaying a generic duplicate error message
  4. 将调用包装到super.persist()并捕获ConstraintViolationException,显示一般的重复错误消息

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.

正如Shervin所说,创建一个JSF Validator是一个好主意(替换)#1,但你应该仍然期待最坏的并捕获ConstraintViolationException。

#2


6  

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

我不同意处理ConstraintException。我写了一个验证器,在保存之前检查重复项,它运行良好。

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:

在你的形式(xhtml)你写:

<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.

这样,它将始终在保存之前验证字段。您甚至可以使用a:support标记来验证焦点何时更改。

#3


2  

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

我的建议是,如果你可以检查一个条件然后检查它,即在你的情况下是UserExists方法调用。抛出异常是昂贵的,并且用于通常与您的控制之外的事物有关的特殊情况,例如:光盘访问等

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

在调用实体添加到数据库之前,通常会在业务逻辑中执行此检查。

#1


6  

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.

即使您在持久保存用户对象之前检查代码中的条件,也有可能有人在您检查的时间和持久保存新用户之间创建重复的loginid。

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.

但是,如果进行显式检查,在UI中显示相应的错误消息会更容易。如果表上有多个约束,捕获ConstraintViolationException将不允许您轻松确定违反了哪个约束。

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

所以我会两个都做。假设您从Seam的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. 在persist()方法中运行查询以确保loginid是唯一的。如果它没有向适当的控件添加错误消息并返回null。
  3. Wrap the call to super.persist() and catch the ConstraintViolationException, displaying a generic duplicate error message
  4. 将调用包装到super.persist()并捕获ConstraintViolationException,显示一般的重复错误消息

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.

正如Shervin所说,创建一个JSF Validator是一个好主意(替换)#1,但你应该仍然期待最坏的并捕获ConstraintViolationException。

#2


6  

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

我不同意处理ConstraintException。我写了一个验证器,在保存之前检查重复项,它运行良好。

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:

在你的形式(xhtml)你写:

<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.

这样,它将始终在保存之前验证字段。您甚至可以使用a:support标记来验证焦点何时更改。

#3


2  

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

我的建议是,如果你可以检查一个条件然后检查它,即在你的情况下是UserExists方法调用。抛出异常是昂贵的,并且用于通常与您的控制之外的事物有关的特殊情况,例如:光盘访问等

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

在调用实体添加到数据库之前,通常会在业务逻辑中执行此检查。