0

I have following xhtml document:

  <h:body>
   <ui:composition template="templates/layout.xhtml">
      <ui:define name="content">
        <c:if test="#{sessionBean.userCode > 0}">
          <h:form id="findStudentForm">
            <p:outputPanel id="resultsPanel">
              <c:if test="#{studentsBean.student != null}">
                <h2><h:outputText value="#{studentsBean.student.fullName}"/></h2>
                <h3>Personal data</h3>
                  . . .
                <p align="center">
                <p:commandButton value="Search students" update="@form">
                  <f:setPropertyActionListener value="#{null}" 
                    target="#{studentsBean.student}"/>
                </p:commandButton>
                </p>
              </c:if>
              <c:if test="#{studentsBean.student == null}">
                <h2>Student search</h2>
                  . . .
                <p align="justify">
                  First name
                  <h:inputText value="#{studentsBean.pattern}"/>
                  <p:commandButton value="Поиск" update="resultsPanel"/>                  
                </p>
                <p:dataTable id="resultsTable" var="student" 
                   value="#{studentsBean.studentsList}" 
                             widgetVar="studentsTable" emptyMessage="No records found">
                  . . . 
                  </p:column>
                  <p:column headerText="Actions">
                    <p:commandButton value="Details" update="@form">
                      <f:setPropertyActionListener value="#{student}" 
                        target="#{studentsBean.student}"/>
                    </p:commandButton>
                  </p:column>  
                </p:dataTable>
              </c:if>
            </p:outputPanel>
          </h:form>
        </c:if>
        <c:if test="#{sessionBean.userCode == 0}">
          <ui:include src="templates/include/error.xhtml"/>
        </c:if>
      </ui:define>  
    </ui:composition>
  </h:body>

Also I have following Managed Bean (StudentsBean): . . .

@Named(value = "studentsBean")
@RequestScoped
public class StudentsBean {

  @Inject
  SessionBean session;
  private Student student = null;
  private String pattern = "";
  private String groupName = "";
  @Inject
  private StudentInterface studentProvider;

  . . .

  public String getPattern() {
    return pattern;
  }

  public void setPattern(String pattern) {
    this.pattern = pattern;
  }

  public List<Student> getStudentsList() {
    List<Student> result = new ArrayList<Student>();
    if (studentProvider != null) {
      try {
        result = studentProvider.findStudents(pattern);
      } catch (StudentException e) {
        session.printError(e.getMessage());
      }
    }
    return result;
  }
  . . .

And finally, I have a class StudentsProvider:

public class StudentProvider implements StudentInterface {

  private Connection connection = null;

   . . .

  @Override
  public List<Student> findStudents(String pattern) throws StudentException {
    List<Student> result = new ArrayList<Student>();
    String addon = "";
    if (pattern.trim().isEmpty()) {
      addon = "TOP 10 ";
    }
    try {
      PreparedStatement statement = connection.prepareStatement(
              "SELECT " + addon + "st_pcode, gr_Name, st_FullName "
              + "FROM students, groups WHERE (st_grcode = gr_pcode) AND (st_FullName LIKE ?) "
              + "ORDER BY gr_Name, st_FullName;", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
      statement.setString(1, pattern + "%");
      ResultSet rs = statement.executeQuery();
      while (rs.next()) {
        result.add(getStudent(rs.getString("st_pcode")));
      }
      rs.close();
      statement.close();
    } catch (Exception e) {
      throw new StudentException("Error reading list: " + e.getMessage());
    }
    return result;
  }

  public StudentProvider() throws StudentException {
    try {
    ConnectionProvider provider = new ConnectionProvider();
    connection = provider.getConnection();
    } catch (ConnectionException e) {
      throw new StudentException("Connect error: " + e.getMessage());
    }
  }

  @Override
  public void finalize() throws Throwable {
    connection.close();
    super.finalize();
  }
}

If variable "pattern" an empty string, PreparedStatement returns 10 "first" records. But if the "pattern" has a content - PreparedStatement finds some records. During debug, seems like PreparedStatement works well and returns result set, but no records shows in the re"sultsTable". In additional, I found, that while updating process method

studentProvider.findStudent(pattern)

calling many times. I think, that number of method calls depends of number of records in the "resultsTable".

Before injection, with hard linked objects everything works fine. What's wrong?

By the way, I can't understand one thing. Say, I have a button

<p:commandButton value="Details" update="@form">
    <f:setPropertyActionListener value="#{student}" 
        target="#{studentsBean.student}"/>
</p:commandButton>

in the each record of "resultsTable" (see xhtml listing before for more details). I found, that this button sometimes doesn't work. If resultsTable is empty at the beginning - button doesn't work, but if resultsTable is NOT empty - button work. So how can I make button always working?

afuzzyllama
  • 6,538
  • 5
  • 47
  • 64
gooamoko
  • 658
  • 12
  • 32
  • Withou reading the whole q' ,datable better be placed inside view or session scope, otherwise it will ne much harder to get it working the right way – Daniel Oct 16 '12 at 06:32
  • I solve problem of data missing in the search result. It was an exception, that was badly handeled. I only need to know now - why getter method for dataTable data calls several times? What number of calls depends of and how can I minimize number of calls. – gooamoko Oct 16 '12 at 08:16
  • Simply don't do business logic in getter methods! – BalusC Oct 16 '12 at 11:19
  • @BalusC Thanks! It's hard for me to think in JSF style yet. I'll remember this golden rule. – gooamoko Oct 17 '12 at 00:34

1 Answers1

2

A better way to do this would be (just a sketch):

// an action method in your backing bean.
// This will call your search method and set the values behid your dataTable
public void searchStudents(String pattern) {
    setStudentsList(findStudent(pattern));
}

After the call finished update your dataTable:

<p:commandButton update="resultsTable" action=#{studentProvider.findStudent(pattern)}"

To answer your second question: Why JSF calls getters multiple times, which implies that putting your business logic methods into getters (without lazy loading) seems to be a bad idea (another related question: JSF calling setter & getter multiple times).

Community
  • 1
  • 1
Akos K
  • 7,071
  • 3
  • 33
  • 46