1 2 Previous Next 22 Replies Latest reply on Apr 22, 2007 10:41 PM by Christian Bauer

    HowTo: When going to a page to enter data, pull from db & ed

    Saeed Iqbal Novice

      Hey guys,

      I have been trying to learn this stuff in a fast pace lately and much of it makes good sense. I was able to create a project in seam-gen some entities from database crud, and some actions. Also modifying the xhtml pages and some configuration to learn Seam.

      Anyway now i have this sample project (will become a real one once i get the hang of Seam). For example it records activity performance per day. So when a person goes to enter an activity for today, it should check database if an activity for him exists for today and pull that record up in the forms so he can edit, if no record exists for that user for today in database he will of course not see anything in the forms and will enter fresh data.

      I created a button with action field going to an action to pull data into the entity and page navigation xml file goes to the editActivity.xhtml page. But the problem is the entitiy never gets the data even after the action method runs. The form is blank even if hibernate sql returns a single row.

      There is no relevant example of this in booking, blog, issues, dvd or any other examples i looked in, i looked in many but im sure i missed some if there are.

      Thanks guys for your help :)

        • 1. Re: HowTo: When going to a page to enter data, pull from db
          Jim Hazen Expert

          Take a look at the documentation on Factory and manager components. They will help you do what you want. Also the blog and messages examples show how you can initialize a contextual variable with DB data when a page is viewed.

          The messages example makes use of a DataTable binder, but you can use @Factory for anything, not just DataTables.

          • 2. Re: HowTo: When going to a page to enter data, pull from db
            Saeed Iqbal Novice

            Oh sweet. I will try that and let you know. I remember seeeing @Factory in one of the files.

            Question for you. What do you think is appropriate place for this based on what I'm doing. In the action bean or in the entity ? Any recommendation on scope?

            Thanks

            • 3. Re: HowTo: When going to a page to enter data, pull from db
              Jim Hazen Expert

              I like to keep my entities clean. Just get/set/toString/equals/hashcode. So I'd put the @Factory on a method in your controller/action/manager Bean. If you need some heavyweight resources that you'd like to clean up, you can use the manager pattern and the @Unwrap annotation. In the case of the manager pattern you have an additional bean dedicated to managing this contextual variable.

              For the most part though, if I'm simply going to initialize a variable that I'll use later within a controller's action method, putting the @Factory on a method within the controller is the way I go.

              • 4. Re: HowTo: When going to a page to enter data, pull from db
                Jim Hazen Expert

                ...and on scope, go as narrow as possible while still being functional. :)

                • 5. Re: HowTo: When going to a page to enter data, pull from db
                  Saeed Iqbal Novice

                   

                  "CptnKirk" wrote:


                  For the most part though, if I'm simply going to initialize a variable that I'll use later within a controller's action method, putting the @Factory on a method within the controller is the way I go.


                  Where would you initialize the variable? In the same object right? and put it @Out? or just @Factory would do?

                  • 6. Re: HowTo: When going to a page to enter data, pull from db
                    Saeed Iqbal Novice

                    Awesome it worked first time i tried.

                    OK i have a suggestion or just brainstorming for what was produced initially by seam-gen in my code.

                    For example in the xhtml it had this

                    <s:decorate id="entryaDecoration" template="layout/edit.xhtml">
                     <ui:define name="label">entrya</ui:define>
                     <h:inputText id="entrya"
                     size="45"
                     maxlength="45"
                     value="#{activityHome.instance.entrya}">
                     <a:support event="onblur" reRender="entryaDecoration"/>
                     </h:inputText>
                     </s:decorate>


                    i had to change the value from that to this "#{activity.entrya}" . so whats up with the *Home.java that our seam-gen creates? whats it purpose? Maybe i am not seeing something i should take into consideration.

                    • 7. Re: HowTo: When going to a page to enter data, pull from db
                      Saeed Iqbal Novice

                      Problem


                      Now one problem was fixed that it picked up stuff from database. But if the row does not exist, and then when i put stuff in the form and say save/submit ... it saves blank values. nothing null

                      This is what my xhtml page has at the bottom. Basically it was all generated by seam-gen (should i stop using seam-gen?)

                      <h:commandButton id="save"
                       value="Save"
                       action="#{activityHome.persist}"
                       disabled="#{!activityHome.wired}"
                       rendered="#{!activityHome.managed}"/>
                      
                       <h:commandButton id="update"
                       value="Save"
                       action="#{activityHome.update}"
                       rendered="#{activityHome.managed}"/>
                      
                       <h:commandButton id="delete"
                       value="Delete"
                       action="#{activityHome.remove}"
                       rendered="#{activityHome.managed}"/>
                      
                       <s:button id="done"
                       value="Done"
                       propagation="end"
                       view="/Activityxhtml"
                       rendered="#{activityHome.managed}"/>
                      
                       <s:button id="cancel"
                       value="Cancel"
                       propagation="end"
                       view="/#{empty activityFrom ? 'ActivityList' : activityFrom}.xhtml"
                       rendered="#{!activityHome.managed}"/>



                      As you can see from my previous post, my values are here
                      #{activity.entrya}
                      Not in
                      #{activityHome.entrya}
                      I dont understand whats the Home stuff.

                      I am pretty sure that save update delete stuff is messing my app up as it points to the activityHome

                      help.

                      While we are here. THis is what i have in my action bean

                      @Out
                       private Activity activity;
                      @Factory("activity")
                       public void actionMethod()
                       {
                       Activity activity= new Activity();
                       try {
                       activity= (Activity) em.createQuery("select o from Activity o where o.userid = :num")
                       .setParameter("num", 1)
                       .getSingleResult(); // the 1 number is temporary will change it
                       }
                       catch (NoResultException ex) {
                       FacesMessages.instance().add("Enter new activity record.");
                      
                       }
                      
                       if(activity!= null){
                       setActivity(activity);
                       }
                       }
                      
                      


                      Scope is event and it is stateless.

                      • 8. Re: HowTo: When going to a page to enter data, pull from db
                        Jim Hazen Expert

                        It's late, but I'll give this a go. Christian or Pete feel free to jump in. It sounds like your mixing your retrieval and persistence mechanisms.

                        @Factory - Method called when a JSF page tries to reference a contextual variable that doesn't exist, but has a named factory method. So if #{activity} isn't found and there is a @Factory method, the method will be called and the contextual variable populated. The variable will have the scope defined by @Factory or if absent, the scope of the enclosing component. @Factory is only called if the contextual variable is null (needs to be created).

                        @Unwrap - Method called on a component that allows the component to manage the creation of a contextual variable. So Component ActivityManager might have an @Unwrap method that puts an Activity into scope referenceable by the EL #{activity}. This method will be called every time the #{activity} variable is referenced or injected into a bean. Because the @Unwrap annotation is on a method within a Seam Component, the component can take advantage of the entire Seam life cycle, including providing tear down logic.

                        EntityHome - These are classes the provide generic DAO capabilities to objects. By using an EntityHome you can Create, Update, Delete a single entity via its primary key. In order to Update or Delete with an EntityHome you must pass the ID of the object to the EntityHome prior to calling update or remove.

                        EJB3 Entity Beans - Seam components that are EJB3 Entity Beans are automatically registered as event scoped components. They have an implicit auto-create when used with JSF pages. So you could @Name("activity") your Activity EJB3 entity bean. And reference it in your JSF page as #{activity}. Seam will call the default constructor and you'll be able to use EL to set values and can inject @In("activity") into the controller that deals with the form action. Beans can have multiple names, and multiple scopes. Read more about the @Role/@Roles annotation for more information.

                        The Seam documentation covers these concepts in greater detail.

                        If all you want to do is supply simple CRUD operations, then you can use an EntityHome. By using an EntityHome it becomes your controller (action method), and thus you don't have to write one. EntityHome can be configured with FacesMessages to notify your users that CRUD operations have completed. Remember that in order to use EntityHome for update and remove you need to pass in an id. The developer guide shows how.

                        Based on the description you can decide whether @Factory or @Unwrap are best suited for your needs.

                        Also, by default JSF will populate an unfilled form with empty values, not null. So if you're trying to populate your #{activity} entity, have a blank form and hit submit. Your controller will be injected with a live object with the form values set to their empty state (empty Strings, 0 ints, etc). If you want these values to be null instead you'll need to write a custom converter. I've written a simple one below. Use the converter method or the <f:converter> tag. The version of MyFaces that ships with JBoss 4.0.5 doesn't seem to want to let you override the default String converter, so you'll need to specify the converter on every input component you'd like it on. This might change on the 1.2 RI, I've heard different things about the RI in the 4.2 CVS tree.

                        @Name("emptytonull")
                        @org.jboss.seam.annotations.jsf.Converter(forClass=String.class)
                        public class EmptyStringToNullConverter implements Converter, Serializable
                        {
                         public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) throws ConverterException
                         {
                         return arg2 == null || arg2.isEmpty() ? null : arg2;
                         }
                        
                         public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) throws ConverterException
                         {
                         return arg2 == null ? "" : arg2.toString();
                         }
                        }


                        Hope this helps. I'm going to crash now.

                        • 9. Re: HowTo: When going to a page to enter data, pull from db
                          Saeed Iqbal Novice

                          Thanks for the information and you are right. I was putting the action logic into EntityHome. Quite funny now i realize. I did a new-form and it created the class i may want to put my stuff in and new-query.

                          I guess i dont want to put my action logic in entityhome, i'll keep it separate as what mainstream Seam users do.

                          Thanks captain. hey you live in san mateo near by to where i live dublin/pleasanton :)

                          • 10. Re: HowTo: When going to a page to enter data, pull from db
                            Pete Muir Master

                             

                            "CptnKirk" wrote:
                            @Unwrap - Method called on a component that allows the component to manage the creation of a contextual variable. So Component ActivityManager might have an @Unwrap method that puts an Activity into scope referenceable by the EL #{activity}. This method will be called every time the #{activity} variable is referenced or injected into a bean. Because the @Unwrap annotation is on a method within a Seam Component, the component can take advantage of the entire Seam life cycle, including providing tear down logic.


                            @Unwrap is most useful for exposing a non-Seam service (e.g. a JavaMail Session) as a Seam component. Its unlikely you want to use it in your app (unless you are providing scafolding), @Factory is the one to use.

                            EntityHome - These are classes the provide generic DAO capabilities to objects. By using an EntityHome you can Create, Update, Delete a single entity via its primary key. In order to Update or Delete with an EntityHome you must pass the ID of the object to the EntityHome prior to calling update or remove.


                            Reading (quickly) the thread, I would suggest taking time to understand the Seam Application Framework as it sounds like you are trying to standard CRUD which it supports ootb. The seamdiscs example is a good example of an app built using the framework (if you can put up with the trinidad and richfaces visual components)

                            EJB3 Entity Beans - Seam components that are EJB3 Entity Beans are automatically registered as event scoped components. They have an implicit auto-create when used with JSF pages. So you could @Name("activity") your Activity EJB3 entity bean. And reference it in your JSF page as #{activity}. Seam will call the default constructor and you'll be able to use EL to set values and can inject @In("activity") into the controller that deals with the form action. Beans can have multiple names, and multiple scopes. Read more about the @Role/@Roles annotation for more information.


                            Not quite, they are only components if the have @Name (in which case they would be CONVERSATION scoped). The "preferred" way to do this is to use Home objects to manage an Entity, rather than expose it directly with @Name, and uses pages.xml for wiring. We could probably do with an example app built using Seam-gen that does a couple of simple CRUD operations

                            • 11. Re: HowTo: When going to a page to enter data, pull from db
                              Jim Hazen Expert

                              Re EJB3 Entities:

                              Not quite, they are only components if the have @Name (in which case they would be CONVERSATION scoped). The "preferred" way to do this is to use Home objects to manage an Entity, rather than expose it directly with @Name, and uses pages.xml for wiring. We could probably do with an example app built using Seam-gen that does a couple of simple CRUD operations

                              Yep, it was late, I forgot I overrode the scope on some of my entities. However there are plenty of times where simple CRUD doesn't fit the bill. If you're actually managing an entity, sure, use a Home. However if you're using a form to populate an entity for another purpose, using Seam to populate a scoped entity and hand it off for further processing has advantages. Of course the entity doesn't need to be an EJB 3 entity. Seam does the same for POJOs.

                              For example I don't think I'd recommend using a Home to populate a search prototype. For search pages, an entity with an event scoped role combined with Hibernate's Criteria API + Example criterion is great.

                              In general if I'm not doing CRUD I prefer to decouple the entity population and the controller doing the work. Prior to Seam I had to populate #{someController.entity.value1}. Now that I can simply work with #{entity.value1} means I have some additional flexibility.

                              What would be really great would be to put out a Seam cookbook. About @Unwrap, Pete is right, most people just want a contextual variable to go from void (not there), to initialized, and that's usually the job for @Factory. However the managed component pattern can be useful not just for scafolding and exposing non-Seam services. For an example you could have a managed component observe many events that happen within your system and change the underlying representation as a result of those observations. With the managed component pattern a component can manage these actions itself and because the component is unwrapped on every access, all callers will have a consistent view. This is a much different use than what Factories provide for.

                              I wasn't sure exactly what the user wanted so figured I'd lay out everything and let him choose.

                              • 12. Re: HowTo: When going to a page to enter data, pull from db
                                Jim Hazen Expert

                                 

                                hey you live in san mateo near by to where i live dublin/pleasanton :)

                                Small world. Maybe I'll see ya at the Seam JavaOne get together.

                                • 13. Re: HowTo: When going to a page to enter data, pull from db
                                  Saeed Iqbal Novice

                                  Thanks Captain and Peter. I'll read it again and make sure I understand what you said

                                  Well how do i know if an object is not a Seam Component? The answer could be apparent to many people but i am not shy to ask what i am not sure of.

                                  • 14. Re: HowTo: When going to a page to enter data, pull from db
                                    Pete Muir Master

                                     

                                    "CptnKirk" wrote:
                                    Yep, it was late, I forgot I overrode the scope on some of my entities. However there are plenty of times where simple CRUD doesn't fit the bill. If you're actually managing an entity, sure, use a Home. However if you're using a form to populate an entity for another purpose, using Seam to populate a scoped entity and hand it off for further processing has advantages. Of course the entity doesn't need to be an EJB 3 entity. Seam does the same for POJOs.


                                    +1

                                    For example I don't think I'd recommend using a Home to populate a search prototype. For search pages, an entity with an event scoped role combined with Hibernate's Criteria API + Example criterion is great.


                                    I prefer using a Query with restrictions in most cases (mainly 'caus the wiring is all done for me) - you can get some pretty complex queries going with just few lines of xml. But definitely an extended entity, or one configured through components.xml is a great way.

                                    What would be really great would be to put out a Seam cookbook.


                                    You should talk to some publishers :) There really aren't many Seam books out atm

                                    For an example you could have a managed component observe many events that happen within your system and change the underlying representation as a result of those observations. With the managed component pattern a component can manage these actions itself and because the component is unwrapped on every access, all callers will have a consistent view. This is a much different use than what Factories provide for.


                                    Interesting use, I've never thought of that - the manual is pretty light on decent uses of @Unwrap (that wouldn't be better done by @Factory), if I get a moment (and you don't mind) I'll try to incorporate that.

                                    Now, if only the forums had a decent search function so people could read all these useful discussions ;)

                                    1 2 Previous Next