I have an entity with a two-field unique constraint. Due to not being able to write a
validator that validates two fields of an entity at once (or am I wrong here?), I ended up
subclassing the EntityHome in order to run my object-level validation before the
superclass update() and persist() get called. However, because the instance entity is
managed, and EntityHome uses the seam-managed persistence context and transaction
management, by the time my code for validation runs, the managed entity has already been
updated by JSF. So when I try to run a select query to determine if the two fields
together are unique, hibernate is automatically flushing the write to the entity, which
throws the EntityExistsException i'm trying to avoid.
I ended up with the following solution, and would like to know if there's a better
way:
| @Name("databaseServerHome")
| public class DatabaseServerHome extends EntityHome<DatabaseServer> {
| @In
| EntityManager entityManager;
|
| @In FacesMessages facesMessages;
|
| @Override
| public EntityManager getEntityManager() {
| return entityManager;
| }
|
| @Override
| @Factory("databaseServer")
| public DatabaseServer getInstance() {
| return super.getInstance();
| }
|
| // ... (removed for clarity)
|
| @Override
| @Rollback(ifOutcome="invalid")
| public String update() {
| // set flush mode to COMMIT so that validateUnique can run a query to
| // check uniqueness without triggering a flush
| // This is required because we have a managed entity with dirty changes
| // (already applied by JSF) and now need to validate them after the
| // changes have been made
| getEntityManager().setFlushMode(FlushModeType.COMMIT);
| if (validateUnique()) {
| return super.update();
| } else {
| return "invalid";
| }
| }
|
| protected boolean validateUnique() {
| DatabaseServer ds = getInstance();
| String existenceQuery = "select ds from DatabaseServer ds where ds.serverName =
:serverName and ds.port = :port";
| try {
| DatabaseServer ds1 = (DatabaseServer) entityManager.createQuery(existenceQuery)
| .setParameter("serverName",
ds.getServerName()).setParameter("port", ds.getPort()).getSingleResult();
| if (ds1 != null && !(ds1.getId().equals(ds.getId()))) {
| facesMessages.add(FacesMessage.SEVERITY_ERROR,"You cannot have two database
servers with the same Name and Port");
| return false;
| } else {
| return true;
| }
| } catch (NoResultException nre) {
| return true;
| }
| }
|
| }
|
One last minor annoyance is that Seam is adding a FacesMessage that reads
"Transaction Failed" when it rolls back - how do I alter this behavior?
Thanks!
View the original post :
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4061382#...
Reply to the post :
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&a...