Reputation: 31
I have the following model
@Entity
class Element {
@Id
int id;
@Version
int version;
@ManyToOne
Type type;
}
@Entity
class Type {
@Id
int id;
@Version
int version;
@OneToMany(mappedBy="type")
Collection<Element> elements;
@Basic(optional=false)
boolean disabled;
}
and would like to allow Type.disabled = true only if Type.elements is empty. Is there a way to do it atomically?
I would like to prevent an insertion of an Element in a transaction while the corresponding Type is being disabled by an other transaction.
Update: sorry I didn't make myself clear. I'm not asking how to trigger the check, but how to prevent a sequence like this:
Transaction 1 checks that Type.elements is empty
Transaction 2 checks that Type.disabled = false
Transaction 1 updates Type and sets disabled = true
Transaction 2 persists a new Element
Transaction 2 commits
Transaction 1 commits
I then have a situation where Type.elements is not empty and Type.disabled = true (broken invariant). How can I avoid this situation? In native SQL, I would use pessimistic locking, but JPA 1.0 does not support this. Can the problem be solved using optimistic locking?
Upvotes: 1
Views: 212
Reputation: 299048
while Bean Validation as suggested by Pascal is more elegant, a quick and easy solution would be entity lifecycle listener methods inside the entity class:
@PrePersist @PreUpdate
protected void validate(){
if(this.disabled && !this.elements.isEmpty()){
throw new IllegalArgumentException(
"Only types without elements may be disabled");
}
}
or better yet, have an Assert class (as in JUnit or Spring that encapsulates the exception throwing):
@PrePersist @PreUpdate
protected void validate(){
Assert.same( // but this implies a bi-directional constraint
this.disabled, this.elements.isEmpty(),
"Only types without elements may be disabled and vice-versa"
);
}
Upvotes: 0
Reputation: 570525
I would like to prevent an insertion of an Element in a transaction while the corresponding Type is being disabled by an other transaction.
I would use the Bean Validation API (JSR 303) and a custom constraint for this purpose. If you are not familiar with Bean Validation, I suggest reading the following entries:
Upvotes: 2