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#4061382

Reply to the post : 
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4061382
_______________________________________________
jboss-user mailing list
[email protected]
https://lists.jboss.org/mailman/listinfo/jboss-user

Reply via email to