1 2 3 Previous Next 33 Replies Latest reply on Dec 12, 2006 2:31 PM by Gavin King

    EntityManager: For newbies or to close gaps in your knowledg

    hdslkf hklsdg Apprentice

      When starting with Seam I had two problems: I knew Spring and Hibernate, but I knew nothing about Seam and EJB3's EntityManager. It took some time to learn Seam, but wrapping my head around the EntityManager was difficult.

      Meanwhile I'm a little more familiar with that stuff and I'd like to share my observations with you guys that just started using Seam. Feel free to contribute - especially since I'm not sure that everything I write is correct ;).

      So, what's to say about the EntityManager? It cares about your entities ;). Those are simple Java objects, with some properties plus their getters and setters. One of the properties must be an Id (mostly a Long) and the class itself must be annotated with @Entity. You can find a lot of examples in the Seam sample applications (like the booking example). In Seam it's important that every Entity even gets a @Name annotation, so that it can be injected into other Seam components.

      Let's assume we have such a entity class which we will call "Entity". The lifecycle of such an entity can include
      - creation
      - reading
      - updating
      - deletion
      The EntityManager provides methods to perform those operations. But first: how to get the EntityManager into my code? It's simple:

      @PersistenceContext
      private EntityManager em;


      Ok, now let's begin by watching how an instance of Entity is born:
      Entity entity = new Entity();

      That's simple. Now the state of this entity is NEW/TRANSIENT. That means that an entity exists in your application, but it has no Id and it does not exist in the database.

      Since we want to make it persistent (i.e. it should be written to the database) we will transform its state into MANAGED.
      em.persist(entity);

      Now the entity is managed by the EntityManager. He takes care of the entity to be written to the database. This needn't happen immediately, he might keep your entity in the cache and write it to the database later. But you can be sure that it will be written.

      Ok, what about reading an existing entity from the database? Therefore we use:
      Entity entity = em.find(Entity.class, Id);

      Every entity has an Id (as I said mostly of type Long) with which you can access it. This is the second parameter here. The first parameter shows that you want to access an instance of the Entity class. After performing the find operation the entity is in state MANAGED, too.

      Ok, as long as an entity is managed every change on it will have an impact on the database. There's no guarantee when the EntityManager will write changes to the database. But it will be done, mostly even immediately, but not later than the em vanishes ;). You have the possibility to trigger database updates manually by
      em.flush();

      This will force the EntityManager to write updates to the DB right now. Mind that this affects all managed entities, not only a single one. Howeverm, usually you needn't call that method.

      If you want it vice versa, namely to reload an entity from the database (maybe because it might have been changed by someone else), use
      em.refresh(entity);


      Now what about removing an entity? It's easy:
      em.remove(entity);

      Now the entity's state becomes REMOVED which means that the entity is scheduled for deletion. You might call flush() if you want to make deletion performed immediately, but usually there's no need to.

      Ok, now it gets a little more complicated. When injecting the EntityManager like I suggested above it has a Transaction Scoped Persistence Context. The persistence context is the "container" the entities live in while they are in state MANAGED. But was does "transaction scoped" mean? First, what is meant by "transaction" at all?

      In EJB3 Stateful oder Stateless beans (recognizable by the homonymous annotations) every method invocation gets wrapped into a transaction. (Just by the way: Whenever a RuntimeException occurs during a transaction a rollback is performed and all changes to data get revoked). So the persistence context is created before invoking that method and removed after the method finished. Afterwards all entities that have been previously managed in this persitsence context become DETACHED.

      Ok, so let's assume you have two methods in your bean. The first one is load(), that calls the find method in order to retrieve an entity in the database. The second method is finish() that might just return a JSF outcome. Between calling those two methods you edit the entity. Will those changes persisted to the database? The anwser is NO.

      After the load() method ended, the EntityManager's persistence context ends, too. All the managed entities now become DETACHED. As a result, those entities - in opposition to transient/new - do have an Id, but they are not managed and changes on those detached entities don't affect the database. When you want to have an entity updated to the database you need to re-attach it to a persistence context. In this case add the following line to the finish() method:
      em.merge(entity);

      Now the entity gets merged into the finish() method's persistence context (remember: every method is a transaction, and every transaction has its own persistence context) and is managed again.

      This works, but it has two disadvantages:
      - you need to call merge (->more code)
      - if you access certain attributes of the entity that have not been initialized during calling find() (e.g. collections of related entities) you will get an exception

      So there's an easy solution: We extend the lifetime of the persistence context so that the entities remain managed during calling multiple transactions/methods. Therefore we change the injection of the EntityManager:
      @PersistenceContext(type=PersistenceContextType.EXTENDED
      private EntityManager em;

      Now the managed entities "live" in an Extended Persistence Context

      You even don't have to call the merge() method since the entities never get DETACHED. So you might ask what is the "normal" (transaction scoped) persistence context good for? Well, it always depends on what you do. The extended context might need more memory as he's always there, even if you don't need him. And whenever entities were changed by other beans (they have their own persistence context) you need to refresh() them explicitely (e.g. in overviews/list pages). The normal EntityManager is just there when you need him and due to his short lifetime he always serves fresh up-to-date data ;)

      Last but not least, when talking about lists: To retrieve not a single entity but a collection of them, use
      List<Entity> entities = em.createQuery("from Entity").getResultList();

      This is not "real" SQL, it's a similar thing called EJBQL. You can even perform restrictions or ordering, e.g.:
      ..."from Entity where lastName=".nameToSearchFor." order by firstName"

      Just use the names of the entity's properties. There's much more to say about EJBQL but this would be too much for this introduction ;).

      Ok, so far for the basics. I hope I was able to give you a brief and comprehensible overview of how to work with the EntityManager.

      As I said, I cannot guarantee everything is 100% correct. And there surely will be some ugly english parts in here (sorry, I'm German, don't beat me *g*). Feel free to add your comments and corrections.

        • 1. Re: EntityManager: For newbies or to close gaps in your know
          Raja Master

          Excellent post. I think you should add it to the wiki. I had some doubts on the managed Persistence Context but its clear now.

          • 2. Re: EntityManager: For newbies or to close gaps in your know
            Pete Muir Master

            Very useful - nice work - might be worth mentioning this in the EJB3/Hibernate forums as it far less confusing than the Hibernate EntityManager reference manual.

            One of the properties must be an Id (mostly a Long) and the class itself must be annotated with @Entity.


            Why a long? (Not come across this before)

            This needn't happen immediately, he might keep your entity in the cache and write it to the database later.

            By default flushes occurs at the method boundary.

            (Just by the way: Whenever a RuntimeException occurs during a transaction a rollback is performed and all changes to data get revoked).


            Just RuntimeException? Not all exceptions? Is it EJB3 or the SeamExceptionFilter that does the rollback?

            So there's an easy solution: We extend the lifetime of the persistence context so that the entities remain managed during calling multiple transactions/methods. Therefore we change the injection of the EntityManager:
            @PersistenceContext(type=PersistenceContextType.EXTENDED
            private EntityManager em;

            Now the managed entities "live" in an Extended Persistence Context


            The Seam Managed Persistence Context takes this further and provides a conversation scoped entity manager. This prevents Lazy Initialisation Exceptions from occuring when accessing entities from earlier requests.

            It needs to be set up in components.xml (see the Configuration section of the reference doc), and then can be accessed via (where mySMPC is the name it was configured under)

            @In(create=true) private EntityManager mySMPC;


            ..."from Entity where lastName=".nameToSearchFor." order by firstName"


            It is recommended not to do this but to do

            em.createQuery("select e from Entity e where e.lastName = :lastname order by e.firstName").setParameter("lastName", lastName).getResultList();


            • 3. Re: EntityManager: For newbies or to close gaps in your know
              hdslkf hklsdg Apprentice

              Wiki
              Yes, I intended to put that in the wiki, but first I wanted it to be reviewed ;).

              Why is Id Long?
              - Integer might be too small *g*
              - Using a hull class (Long instead of long) makes it easy to have entities without Id (necessary in transient/new or removed state), since the Id can be "null" then. You could use long (the primitive, not the hull class), but then you would need to explicitely define a "no id state" (e.g. -1 or 0) as far as I know.
              - It's also possible to define other "simple" classes, e.g. String as an Id. This could be useful e.g. for unique usernames. Even "complex" classes can be used via @EmbeddedId, and those complex classes need to be annotated with @Embeddable... but ...WHOW... this is going way to far for a newbie tutorial and I cannot think of many useful cases ;).

              Flush at method boundary
              Thanks for that hint. That's what I didn't know. However, sometimes it's useful to flush before, e.g. to easily recognize database constraint violations and then add a message and perform a rollback.

              Rollback on Exceptions
              - There's something I'd like to add: When saying "rollback" I usually talk about rollbacks of EJB transactions! Usually changes are made to an entity during a method invocation. If everything works fine, flush() is performed at method end. If an exception occured or setRollbackOnly() was called, then flush() will not be called. So the database remains untouched, but the entity keeps its "dirty" data for now. That's how EJB transactions work. Other case: flush() is explicitely called in the method. Then EJB starts a database transaction and sends the update/insert/delete statements to the database. If the method ends without exceptions, then the database commit will be called, otherwise the database transaction will be rollbacked. So please distinguish between EJB and database transactions ;). I hope I made clear how they work together. (All I said here is what I observed, and it seems to be sensible to me).

              - Well, I talked about RuntimeExceptions as you cannot compile without catching "normal" exceptions. Ok, you can add "throws Exception" to your method signature in order to see what happens if normal exceptions occur. This doesn't make sense since the page you're on will crash, but even in this case a rollback will be performed (I just tested it ;)). But all in all you're right, rollbacks happen after all types of exceptions, but usually you catch normal exceptions ;).

              btw: It's never a fault to add try...catch... around critical blocks in order to keep your app in a fine state. Catch exceptions, add a message to the user, and explicitely use ejbctx.setRollbackOnly() (@Resource javax.ejb.SessionContext ejbctx). Otherwise your app will crash with ugly exception stacktraces shown to the user - and though the transaction might be rollbacked automatically this just ain't beautiful ;).

              - I think that it's EJB3 that cares about the exception since it even cares about the transaction. But I'm not 100% sure about that. Maybe the experts can say something about that ;).

              Seam Managed Persistence Context
              I must confess that I never ran into LazyInitializationExceptions (abbr. LIE). I use an Extended Persistence Context in a Conversation scoped Stateful Session Bean. And when accessing related entities the EntityManager lazily fetches them without complaint. Don't ask me why. Maybe you can add a case where the LIE occurs.

              List, setParameter
              Jep, you're right ;).

              • 4. Re: EntityManager: For newbies or to close gaps in your know
                Justin Newbie

                 

                "bfo81" wrote:

                Seam Managed Persistence Context
                I must confess that I never ran into LazyInitializationExceptions (abbr. LIE). I use an Extended Persistence Context in a Conversation scoped Stateful Session Bean. And when accessing related entities the EntityManager lazily fetches them without complaint. Don't ask me why. Maybe you can add a case where the LIE occurs.


                There is a 'subtle' difference between an extended persistence context (EPC) and the seam managed persistence context (SMPC).

                The EPC allows a conversational component's entity manager to manage the entities in a 'long running' transaction. The length of the transaction is usually scoped to the lifespan of the component (typically a stateful session bean).

                Lets assume we have the following entity relationship:
                Customer 1 ------ * Address
                .. and that the addresses are lazily loaded.

                @Stateful
                public class EditCustomerBean implements EditCustomer {
                
                 @PersistenceContext(type=PersistenceContextType.EXTENDED)
                 private EntityManager em;
                
                 private Customer customer;
                
                 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
                 public void init(long customerId) {
                 customer = em.find(Customer.class, customerId);
                 }
                
                 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
                 public void addAddress(Address address) {
                 customer.addAddress(address);
                 }
                
                
                 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
                 public Customer getCustomer() {
                 return customer;
                 }
                
                 @Remove
                 public void end() {
                 em.flush();
                 }
                }
                

                Prior to ejb3 EPM's transactions typically spanned the remote method call (if your methods were invoked in a JTA tx) - and the Customer object would therefore become DETACHED at the end of the init() method. Calling addAddress() would then result in a LIE as the Customer object is not associated with the current (new) transaction.

                The lifespan of the EPC entity manager however is extended and therefore spans the lifespan of the stateful session bean (sort of). So in the code snippet above, a client could call init() and then addAddress() without having to rely on some re-initialisation of the state of the customer on the second call (usually from some saved state detached state stored in the bean).

                Now the important part - Assuming the addresses are lazily loaded - If a (remote) client calls init() and then getCustomer() and attempts to access the addresses outside the scope of the entity manager - you will get a LIE whether the EntityManager is extended or not. This is fairly intuitive - the Customer object has left the managed environment of the stateful session bean and is no longer associated with the EPC.

                The SMPC takes the concept of an EPC a little further by integrating the JSF lifecycle with that of the stateful component. Effectively what the SMPC achieves is the removal of LIE when traversing objects outside the scope of your session bean (there's more to it than that - but for now that will do). So in your JSF, if you traversed the customer --> addresses relationship (after outjecting a customer object) you'll avoid the LIE issue.

                For more information on EPC and application transactions see http://docs.jboss.org/ejb3/app-server/tutorial/index.html

                My experience with using an EPC is still somewhat new - and there are a few gotchas - like marking methods as TX.NOT_SUPPORTED when you don't want to flush at the end of the method etc - so any corrections/contributions are welcome.

                • 5. Re: EntityManager: For newbies or to close gaps in your know
                  hdslkf hklsdg Apprentice

                  1) TX.NOT_SUPPORTED is quite interesting, too. I mean sometimes you have a backing SFSB that provides additional functionality e.g. validation that can't be done directly in JSF (e.g. comparing two entered passwords like in user registration). You sure don't want flush() to be called after that ;). So that's an important tip, thanks.

                  2) But I still have problems understanding those LazyInitalisationExceptions. I mean, look at that example code:

                  Let's assume we want to edit a person (first/last name, birthday...) and we have a select menu to choose some friends (that are also persons here)

                  @Stateful
                  @Scope(ScopeType.CONVERSATION)
                  @Name("personEditor")
                  public class PersonEditorBean implments PersonEditor {
                  
                   @In(required=false) @Out(required=false)
                   private Person person;
                  
                   @PersistenceContext(type=PersistenceContextType.EXTENDED)
                   private EntityManager em;
                  
                   @RequestParameter
                   private Long personId;
                  
                   @Begin
                   public String startEditing() {
                   person = em.find(Person.class, personId);
                   return "editorPage";
                   }
                  
                   ....
                  }


                  Now the editor page looks like that:

                  ...
                   <h:selectManyMenu value="#{person.friends}" ...
                  


                  Guess what? In this case there is NO LazyInitalisationException, though the person's getFriends() method is being called by JSF, what leads to a lazy fetching (I can see it in the logs, there's really no eager fetching).

                  QUESTION: When accessing collections of seam components, why is there no LIE? Do those components remain managed?

                  PS: When using normal (i.e. transaction scoped) persistence context instead of the extended one there are exceptions of course.





                  • 6. Re: EntityManager: For newbies or to close gaps in your know
                    Pete Muir Master

                    The design pattern (manual flushing) which is supported by TX.NOT_SUPPORTED is more elegantly (IMO) provided by @Begin(flushMode=FlushModeType.MANUAL) (which is due for Seam 1.1).

                    • 7. Re: EntityManager: For newbies or to close gaps in your know
                      hdslkf hklsdg Apprentice

                      Sounds good, too. But: I don't want to use the CVS version since I want to use Seam in a production environment. I looked at the CVS files, but I don't know what exactly happens with the new flushMode property of Conversation.java. I also tried to get the Hibernate session in order to set its flush mode, but I didn't suceed.

                      Can you tell me how to manually set the flush mode with a single annotation or a single code block? As I said, I want to turn auto-flushing off, since I have some methods that exist for other purposes than changing data ;).

                      • 8. Re: EntityManager: For newbies or to close gaps in your know
                        Pete Muir Master

                        EJB3 doesn't have FlushMode.Never but an extension is provided by Hibernate.

                        Seam does this:

                        ( (Session) entityManager.getDelegate() ).setFlushMode(FlushMode.NEVER);


                        (from org.jboss.seam.util.Persistence). So that should work.

                        • 9. Re: EntityManager: For newbies or to close gaps in your know
                          hdslkf hklsdg Apprentice

                          That's strange. http://fisheye.labs.jboss.com/viewrep/JBoss/jboss-seam/src/main/org/jboss/seam/util/Persistence.java?r=MAIN shows your code. But it doesn't work for me since getDelegate() returns an instance of org.hibernate.ejb.EntityManagerInstance. So I had to use this:

                          ( (EntityManagerImpl) em.getDelegate() ).getSession().setFlushMode(FlushMode.NEVER);


                          Now there aren't any auto-flushes anymore. But: explicit calls of flush() don't work either.
                          javax.persistence.TransactionRequiredException: no transaction is in progress
                          So I think you must explicitely open and close transactions... what is not only a bit silly since it makes me lose some of EJB3s convenience stuff. It even doesn't work for me now:
                          ejbCtx.getUserTransaction().begin()
                          em.getTransaction.begin()
                          ( (EntityManagerImpl) em.getDelegate() ).getSession().beginTransaction()
                          ( (EntityManagerImpl) em.getDelegate() ).getSession().getTransaction().begin()
                          ... they all throw Exceptions

                          So this is where I'm stuck ^^.

                          • 10. Re: EntityManager: For newbies or to close gaps in your know
                            Chua Khoon Yong Novice

                            dear bfo81,

                            I got some problems with Entity Manager and still troubleshooting, hope you could help.

                            What i did was to make a sample war file by piecing the seam examples together:

                            1. First use example/portal and add facelets and tomahawk support

                            2. Modify to include EJB3 (changing component.xml, persistence.xml, jboss-beans, ejb-jar.xml). I refer example/issues for the EJB3 portion.

                            I encountered problem when retrieving the entitymanager which seems to be null after i compare variable "em" with null.

                            @PersistenceContext(unitName="entityManager")
                            private EntityManager em;


                            I couldn't find whats wrong with those xml files (which is reference from example/issues)

                            I would like to ask if we would deploy EJB3 using WAR file?

                            Hope you could point me in the right direction ... quite tiring to troubleshoot because new to this.

                            My main purpose is to use seam + portlet + facelets + tomahawk + ejb3.

                            Many thanks.

                            • 11. Re: EntityManager: For newbies or to close gaps in your know
                              Chua Khoon Yong Novice

                              dear all,

                              Not sure if my problem is caused by deploying portlet using WAR file.

                              See http://docs.jboss.org/ejb3/app-server/reference/build/reference/en/html/entityconfig.html

                              section 3.3.

                              If this is the case, then how to deploy portlet using EAR file, so that could use EJB3. What happens to the context root for application.xml?

                              I hope my understanding is correct :)
                              Many thanks to anyone that can shed some light on the above issue.

                              Cheers.

                              • 12. Re: EntityManager: For newbies or to close gaps in your know
                                hdslkf hklsdg Apprentice

                                Hi chuaky,

                                I would try to use @PersistenceContext without unitName. But I can't say anything without seeing your configuration. And I must confess that I'm not an EJB3 expert. I just wanted to write my knowledge down here in order to find out what's wrong and right and to learn something more (especially about transactions and the different ways to apply them - I still have open questions about that), and finally turn it into a wiki entry.

                                However, I highly suggest that you open a new thread since your issue might need a longer discussion. And that wouldn't fit into that wiki-oriented topic here ;).

                                • 13. Re: EntityManager: For newbies or to close gaps in your know
                                  Chua Khoon Yong Novice

                                  dear bfo81,

                                  Many thanks for the suggestion, would open a new thread for this issue.
                                  Cheers.

                                  • 14. Re: EntityManager: For newbies or to close gaps in your know
                                    hdslkf hklsdg Apprentice

                                    So finally, I found a solution for my problem:

                                    I have a bean that has not only methods writing to the database, but also provide some other stuff. And I don't want to have auto-flushes after the latter.

                                    You should prevent EJB from auto-flushing and write to the database explicitely when you need it by em.flush().

                                    There are several ways to switch auto-flushing off:

                                    • @Begin(flushMode=FlushModeType.MANUAL)

                                      But this is still a feature from the future (i.e. only in the CVS version) and should not be applied in production environments.


                                    • Try to set the flush mode on the Hibernate Session and manually perform transactions ... and tell me how you succeeded (i.e. this could work but you better don't waste your time with this unless you're a real expert ;)).


                                    • @TransactionManagement(TransactionManagementType.BEAN)

                                      Usually Beans have Container Managed Transactions. But with this annotation you tell EJB3 that you want to care about transactions yourself (User Managed Transactions). Well, and this is what you also have to do then, of course. Back to stoneage - don't do this ;).


                                    • @TransactionAttribute

                                      As a default all methods have the transaction attribute REQUIRED. That means they are all wrapped by a transaction. If you want to change this you can use the transaction attribute NOT_SUPPORTED (btw: there are even more types, for the sake of completeness). There are two possibilities:

                                      - To prevent a single method from being run in a transaction (which will lead to auto-flushes) annotate it with @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED). If you have multiple methods like this you need multiple annotations ;).

                                      - Or annotate the class itself with @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) (all methods will "inherit" this). Then restore the default behaviour to some special methods (e.g. store, delete) by annotating them with @TransactionAttribute(TransactionAttributeType.REQUIRED)

                                      Depends on what is shorter for you. I annotated my class with NOT_SUPPORTED and the store and delete method with REQUIRED. That's only three annotations... nice :).


                                    1 2 3 Previous Next