3 Replies Latest reply on May 28, 2007 11:47 AM by fernando_jmt

    Domain model duplicates validation

    goku2

      If a have a entity like this(is just an example :D)

      @Entity
      @Name("person")
      public class Person implements Serializable {
       private Long id;
       private String firstName;
       private String lastName;
       private int age;
      
       @Id
       @GeneratedValue
       public Long getId() {
       return id;
       }
      
       public void setId(Long id) {
       this.id = id;
       }
      
       @NotNull
       @Length(max=50)
       public String getFirstName() {
       return firstName;
       }
      
       public void setFirstName(String firstName) {
       this.firstName = firstName;
       }
      
       @NotNull
       @Length(max=50)
       public String getLastName() {
       return lastName;
       }
      
       public void setLastName(String lastName) {
       this.lastName = lastName;
       }
      
       @Min(0)
       public int getAge() {
       return age;
       }
      
       public void setAge(int age) {
       this.age = age;
       }
      }
      


      And i would like to know how can i create a validation method telling seam to use the firstName and the lastName as a compound id for the entity without mapping that to the database?
      I want to use the id property as the id for the mapping but the logic has to be in a method. If this logic is in a @PrePersist annotates method i can only compare the entity properties but not compare them with the persisted ones.

      I would like to know how can i compare if there is an existent entity in the data source like the one i'm trying to persist. Maybe i have to override the equals method?
      At witch layer do i have to do this validation rule? It would be ideal to have that logic in the domain model and not have it in some stateless or statefull bean.

      Thanks in advance

      Humber

        • 1. Re: Domain model duplicates validation
          fernando_jmt

          I don't know what exactly you mean with "without mapping that to the database", but anyway I have solved something similar as follows:

          @Entity
          @Table(name = "person", uniqueConstraints = @UniqueConstraint(columnNames = {"firstname", "lastname"}))
          public class Person {
           @Id
           private Long id;
           @Column(name = "firstname")
           private String firstName;
           @Column(name = "lastname")
           private String lastName;
           private String address;
          
           public Long getId() {
           return id;
           }
          
           public void setId(Long id) {
           this.id = id;
           }
          
           public String getFirstName() {
           return firstName;
           }
          
           public void setFirstName(String firstName) {
           this.firstName = firstName;
           }
          
           public String getLastName() {
           return lastName;
           }
          
           public void setLastName(String lastName) {
           this.lastName = lastName;
           }
          
           public String getAddress() {
           return address;
           }
          
           public void setAddress(String address) {
           this.address = address;
           }
          }
          
          


          With above, the validation is done in database layer, but it is caught by JPA and it throws a javax.persistence.EntityExistsException. It works for me in the sense I don't have to write any special login in a Session Bean to validate this.

          HTH.

          • 2. Re: Domain model duplicates validation
            goku2

            Thanks 4 the reply Fer!

            This works great.


            I don't know what exactly you mean with "without mapping that to the database"

            Sorry about that. I want to validate this uniqueness in my models. But is also great to have then validated in the database to.
            But in some weird case where my validation require some kind of twisted logic using some properties from the Person entity and all the other entities already persisted, is there a clean way to add this logic in the model? Or this is conceptually wrong?
            I think that using an Staless or Statefull bean for this kind of validation may mix up the controller with the model.

            Pleas correct me.

            The validation you gave me works great. The only complain is that a get some error logs about:
            10:36:54,795 ERROR [JDBCExceptionReporter] ERROR: duplicate key violates unique constraint "person_name_key"
            10:36:54,795 ERROR [AbstractFlushingEventListener] Could not synchronize database state with session
            org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
             at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
             at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
            


            Which is a little annoying :)

            Thanks again

            Hey, i'm your neighbor! From Paraguay :D



            • 3. Re: Domain model duplicates validation
              fernando_jmt

              Hi.


              But in some weird case where my validation require some kind of twisted logic using some properties from the Person entity and all the other entities already persisted, is there a clean way to add this logic in the model? Or this is conceptually wrong?


              For me, putting validation logic in your model is nasty. And it's conceptually wrong. If you want to validate something related to one or several entities, and you don't have another way to do it (according your requirements) then you should perfom such validation in your controller (SLSB or SFSB).

              The example I gave you it was recently adopted by me for validate duplicates for an entity (of course when the properties are not the @Ids). Time ago I was doing this validation in a session bean, something as follows:
              public void persis(Person entity){
              
              try {
               em.createQuery("select p from P where p.lastName=:lastName and
               p.firstName = :firstName).setParameter("lastName",
              entity.lastName).setParameter("firstName",
              entity.firstName).getSingleResult();
              
              //user exists, then throw some AlreadyExistException.
              } catch (NoResultException e) {
               em.persist(entity);
              }
              
              }
              


              But the above code involves two SQL's:
              select from person ...where lastname....
              insert into person...... (if the above sql does not return value)
              


              But delegating this validation to DB layer (@UniqueConstraint) the only SQL will always be:
              insert into person....
              


              So, in order to reduce the DB round trip I decided to use DB approach for this case. Of course, if you are free to make changes in the database schema. I think this is total portable, because I don't know some database server that does not allow to use "UNIQUE" constraints.

              The validation you gave me works great. The only complain is that a get some error logs about:


              Yes, this is annoying, I ask the same time ago, see below link (I din't try it yet myself):
              http://www.jboss.com/index.html?module=bb&op=viewtopic&t=98560




              Hey, i'm your neighbor! From Paraguay :D


              Nice to hear it.


              Cheers.