[jboss-user] [JBoss Seam] - Transaction management in EntityHome subclass
mbertelsen
do-not-reply at jboss.com
Fri Jul 6 12:20:42 EDT 2007
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
More information about the jboss-user
mailing list