Playframework 验证:保存前检查唯一性

Playframework 验证:保存前检查唯一性,playframework,Playframework,我正在开发一个带有Play框架的web应用程序。我的应用程序有一个用户类,该类又有一个用户名和一个电子邮件属性。相当标准的东西。然而 当新用户通过表单(signup,html)注册时,我想检查用户名和密码是否唯一,如果不唯一,将它们重定向回表单并在那里显示消息 我已经想到了一些解决方案,其中没有一个是特别优雅的,在我看来,必须有一种简单的方法来检查用户名/电子邮件在数据库中是否唯一,而无需对表本身施加约束(插入重复值时会导致运行时错误) 所以。。。有人遇到过同样的问题吗?你是怎么解决的呢?我在一

我正在开发一个带有Play框架的web应用程序。我的应用程序有一个用户类,该类又有一个用户名和一个电子邮件属性。相当标准的东西。然而

当新用户通过表单(signup,html)注册时,我想检查用户名和密码是否唯一,如果不唯一,将它们重定向回表单并在那里显示消息

我已经想到了一些解决方案,其中没有一个是特别优雅的,在我看来,必须有一种简单的方法来检查用户名/电子邮件在数据库中是否唯一,而无需对表本身施加约束(插入重复值时会导致运行时错误)


所以。。。有人遇到过同样的问题吗?你是怎么解决的呢?

我在一个排班系统中做了类似的事情,以防止同一个人轮班重叠。在该模型中,它使用一个
@PrePersist
方法来查询数据库,如果发现任何冲突,则抛出一个自定义异常

然后在控制器中捕获异常(保存对象时将抛出异常),并重定向回表单

在模型中:
您必须使用数据库约束并适当地处理异常,或者使用锁定(这可能会牺牲性能)。如果您试图在最后一分钟进行检查,您永远不会知道在检查和提交之间是否有另一个请求潜入用户名中

虽然不常见,但也有可能发生(想象一下网络速度很慢,用户提交了很多次)。嗯,你最好只是正确地处理这个问题,而不是希望不太可能的事情永远不会发生


如果你愿意,我可以用代码详细说明。虽然听起来你可能已经知道如何做了(但我们只是在寻找一个更优雅的解决方案)。

我写了一个UniqueCheck Valitdation。你可以在这里找到关于它的信息 您可以在这里找到支票的测试


我建议在数据库中定义额外的唯一约束。

非常感谢您的建议。我通过在提交表单时检查它来解决这个问题,如果用户名或电子邮件已经存在于数据库中,我就不保存它。没问题。注意-在您的应用程序上下文中,这可能不是什么大问题,但您应该知道该解决方案存在竞争条件;i、 e.最终可能会出现重复。任何无共享体系结构本质上都必须依赖数据库来处理并发性。我很惊讶在play框架中还没有更多的讨论,但是下面的链接在Rails中讨论了同样的问题。(查看下半部分-此处适用“固有倾向”)。
@PrePersist
public void prepareToInsert() {
    List<AgentShift> conflicts = find("agent=?1 and (start_time between ?2 and ?3 or end_time between ?2 and ?3)",
        agent,
        sql_datetime_formatter.print(scheduled.getStart()),
        sql_datetime_formatter.print(scheduled.getEnd())).fetch();
    if (!conflicts.isEmpty()) {
        throw new SchedulingException("New shift for " + agent +
            " overlaps existing shift which goes from " +
            sql_datetime_formatter.print(conflicts.get(0).scheduled.getStart()) + " to " +
            sql_datetime_formatter.print(conflicts.get(0).scheduled.getEnd()), conflicts);
    }

}
public static void create(@Valid AgentShift object) {
    ...
    try {
        object._save();
        ...
    }
    catch (SchedulingException e) {
        flash.error("conflict with existing shift", e.getConflicts());
        redirect(request.controller + ".blank", object._key());
    }
}