3 Replies Latest reply on Dec 18, 2007 4:12 PM by pmuir

    how to dis-manage entities?

    gsegura

      Hello, I got into this kind of chicken-egg problem related to entity versioning:

      There is an entity Course which has a collection of CourseNote.
      When adding a CourseNote to the collection I have to obtain a managed instance of Course, whose version field is been incremented implicitly when the flush occurs (because it is been managed).

      And that is the problem because when more than one user are inserting CourseNotes to the collection, the second one will get an optimisticlockexception at the time he tries to merge his instance of the course

      I do need to access the course during CourseNote creation to do some work (so entityManager.getReference is not enough) but that very action is causing the course to get managed and involved in the transaction, which I do not want to happen.


      //validation omited
      Ticket ticket = (Ticket)entityManager
       .createQuery("select t from Ticket t where t.code=#{register.code}")
       .getSingleResult();
      
      CourseNote courseNote = ticket.getCourse().enroll(user) ;
      entityManager.persist(courseNote) ;
      
      //...
      entityManager.flush() ;
      
      



      class Course {
       public void enroll(User user) {
       CourseNote cn = new CourseNote(user,this) ;
       if(!getCourseNotes().contains(c)) {
       getCourseNotes().add(c) ;
       usuario.getCourseNotes().add(c) ;
       return c ;
       }
       throw new IllegalStateException(
       new StringBuilder(50)
       .append("User ")
       .append(user.getId())
       .append(" is already enrolled in the course ")
       .append(this.getId()).toString()) ;
       }
      }
      


      I kindly request some pattern or tip.
      Please, some advice on this will be very very appreciated

        • 1. Re: how to dis-manage entities?
          gsegura

          perhaps the topic name was not the best, but I think its a fair question.
          So far, only strategy to avoid the entity which holds the collection to get updated is to resort to deal with id alone, a not very object-oriented way to go, so instead of retrieving the ticket.course object fetch just the id:

          Integer idCourse = (Integer)entityManager
           .createQuery("select t.course.id from Ticket t where t.code=#{register.code}")
           .getSingleResult();



          But I don't know if dealing with IDs is the proper way to go with respect to ORM techniques.

          At the same time this makes think of another issue: the implementation of master-detail editions, which at first, for the neophyte like me, feels natural to handle using nested conversations and sharing full objects but the preferred way to go is using entityhome and its passing-just-the-id technique, again a not very OO-ish way IMHO.



          • 2. Re: how to dis-manage entities?
            gsegura

            Probably I'm missing some fundamental knowledge about this issue, I do not think this scenario is that uncommon:

            how to retrieve an entity by query (or otherwise) in 'read-only mode' that is, avoid updating it at flush time?

            Given that it is been managed by EntityManager, it will be implicitly updated (that is, even without calling EntityManager.merge explicitly), right?

            Or could be that, in general, I am using the wrong approach/asking the wrong question?

            • 3. Re: how to dis-manage entities?
              pmuir

               

              "gsegura" wrote:
              And that is the problem because when more than one user are inserting CourseNotes to the collection, the second one will get an optimisticlockexception at the time he tries to merge his instance of the course


              I would just used managed entities at all times.

              At the same time this makes think of another issue: the implementation of master-detail editions, which at first, for the neophyte like me, feels natural to handle using nested conversations and sharing full objects but the preferred way to go is using entityhome and its passing-just-the-id technique, again a not very OO-ish way IMHO.


              I don't really understand this statement. Why can't you use EntityHome and nested conversations? EntityHome uses objects when inside the conversation (you just pass in the id to get started, probably from outside the conversation). Why is EntityHome not very ooish?

              JPA doesn't have a concept of read only entities afaik.