问题
Given the Play Framework 2.3 Computer Database sample application, I would like to practice adding a unique constraint on an attribute. Let's say I want the name
attribute of the Computer
class to be unique. I've tried to do this by adding a validate()
function (and a getter) to Computer.java
:
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;
}
This check works when creating new records in the database, however, this now causes a validation error when you update a Computer object but don't change the name. Is there a way to add a uniqueness constraint, similar to Rails? How can I validate uniqueness in Play?
Thanks!
UPDATE: see the answer by davide.
I ended up using the @Column(unique = true)
constraint from the javax.persistence API. This doesn't generate an error in Play forms; instead, it throws a PersistenceException
. Therefore I had to add change my controller to achieve the behavior I wanted. Both the create()
and update()
actions need a try/catch like this:
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));
}
UPDATE 2: each of the answers below is a possible solution
回答1:
You need to exclude current entity from unique checking, i.e. like that:
if(Computer.find.where().eq("name", getName()).ne("id", getId()).findRowCount() != 0){
errors.add(new ValidationError("name", "Name must be unique."));
}
It will give you SQL query during update:
select count(*) from computer t0 where t0.name = 'Foo' and t0.id <> 123
And this during create:
select count(*) from computer t0 where t0.name = 'Foo' and t0.id is not null
P.S. ne()
expression stands for Not Equal To and of course this approach assumes that your name
field is Required
Edit: I sent you pull request with working solution, all you need is to add hidden field in your editForm
like:
<input name="id" type="hidden" value='@computerForm("id").value'/>
Other thing is that you can simplify your model, i.e. don't need for getters for public fields.
回答2:
I not sure if this answer your question, because I'm not familiar with Ruby syntax.
To "create a uniqueness constraint in the database" you can use the javax persistence API. Ebean will also recognize this.
To have a plain uniqueness constraint which involves a single field, you can use the @Column annotation:
@Entity
public class Computer extends Model {
...
@Column(unique = true)
public String name;
...
}
If you need some combination of fields to be unique, instead use the @Table annotation
@Table(
uniqueConstraints=
@UniqueConstraint(columnNames={"name", "brand"})
)
@Entity
public class Computer extends Model {
...
public String name;
public String brand;
...
}
I hope it helps!
来源:https://stackoverflow.com/questions/28906096/play-framework-2-3-how-to-add-unique-constraint-to-sample-application