【问题标题】:Play Framework 2.3 How to add unique constraint to sample applicationPlay Framework 2.3 如何为示例应用程序添加唯一约束
【发布时间】:2015-03-06 19:21:30
【问题描述】:

鉴于Play Framework 2.3 Computer Database sample application,我想练习在属性上添加唯一约束。假设我希望 Computer 类的 name 属性是唯一的。我试图通过向Computer.java 添加一个validate() 函数(和一个getter)来做到这一点:

public List<ValidationError> validate() {

    List<ValidationError> errors = new ArrayList<ValidationError>();

    if(Computer.find.where().eq("name", getName()).findRowCount() != 0){
        errors.add(new ValidationError("name", "Name must be unique. That value is already taken."));
    }

    return errors;
}

public String getName() {
    return name;
}

在数据库中创建新记录时,此检查有效,但是,当您更新计算机对象但不更改名称时,这会导致验证错误。有没有办法添加uniqueness constraint, similar to Rails?如何在 Play 中验证唯一性?

谢谢!

更新:见answer by davide

我最终使用了 javax.persistence API 中的 @Column(unique = true) 约束。这不会在 Play 表单中产生错误;相反,它会抛出一个PersistenceException。因此,我必须添加更改我的控制器以实现我想要的行为。 create()update() 操作都需要这样的 try/catch:

 try {
     computerForm.get().save();
 } catch (PersistenceException pe) {
     flash("error", "Please correct errors below.");
     formData.reject("name", "Name conflict. Please choose a different name.");
     return badRequest(createForm.render(computerForm));
 }

更新 2:以下每个答案都是可能的解决方案

【问题讨论】:

  • PersistenceException 对于这个恕我直言来说太宽泛了,但这是你的选择
  • @biesior 这是一个很好的观点。我想这不是最好的解决方案。你会建议捕获一个不同的异常吗?

标签: forms playframework playframework-2.3


【解决方案1】:

您需要从唯一检查中排除当前实体,即:

if(Computer.find.where().eq("name", getName()).ne("id", getId()).findRowCount() != 0){
     errors.add(new ValidationError("name", "Name must be unique."));
}

它会在更新期间为您提供 SQL 查询:

select count(*) from computer t0 where t0.name = 'Foo' and t0.id <> 123 

在创建过程中:

select count(*) from computer t0 where t0.name = 'Foo' and t0.id is not null 

P.S. ne() 表达式代表 Not Equal To,当然这种方法假定您的 name 字段是 Required

编辑:我向您发送了带有有效解决方案的拉取请求,您只需在 editForm 中添加隐藏字段,例如:

<input name="id" type="hidden" value='@computerForm("id").value'/>

另一件事是您可以简化模型,即公共字段不需要 getter。

【讨论】:

  • 我试过了,问题是即使在更新时,从请求中绑定的数据还没有id,因此getId()在这个@中始终为空987654331@ 声明。试着把这行放在if 之前,你会明白我在说什么:Logger.debug("current id: " + getId());
  • 通常我在发布此答案之前测试了该方法(在其他项目而不是计算机示例上)并且没关系。将其发布到某个地方(即临时 Github 存储库),以便我检查问题所在。
  • 检查编辑并拉取请求,一个小改动就可以工作
【解决方案2】:

我不确定这是否能回答您的问题,因为我不熟悉 Ruby 语法。

要“在数据库中创建唯一性约束”,您可以使用javax persistence API。 Ebean 也会识别这一点。

要拥有涉及单个字段的简单唯一性约束,您可以使用@Column annotation

  @Entity
  public class Computer extends Model {
    ...

    @Column(unique = true)
    public String name;

    ...
  }

如果您需要某些字段组合是唯一的,请改用 @Table annotation

  @Table(
        uniqueConstraints=
            @UniqueConstraint(columnNames={"name", "brand"})
    )
  @Entity
  public class Computer extends Model {
    ...

    public String name;
    public String brand;

    ...
  }

希望对你有帮助!

【讨论】:

  • 是的,我已经尝试输入@Column(unique = true),但是这会在数据库级别引发错误,并且在填写 Play 表单时不会产生验证错误,这正是我需要的。
  • 我通常做的是将保存或更新包装在 try-catch 块中,以捕获引发的异常,然后我重定向回表单,使用 flash 范围发出错误信号跨度>
猜你喜欢
  • 2015-04-19
  • 1970-01-01
  • 1970-01-01
  • 2017-05-05
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-19
  • 2014-07-09
相关资源
最近更新 更多