public void testProjectOuterJoinTeamLeaderAddressTeamMembersAddressPhonesWhereProjectName() {
    ReadAllQuery query = new ReadAllQuery();
    query.setReferenceClass(Project.class);
    query.setSelectionCriteria(
        query
            .getExpressionBuilder()
            .get("name")
            .equal("Problem Reporting System")
            .or(query.getExpressionBuilder().get("name").equal("Bleep Blob")));

    ReadAllQuery controlQuery = (ReadAllQuery) query.clone();

    Expression teamLeader = query.getExpressionBuilder().getAllowingNull("teamLeader");
    query.addJoinedAttribute(teamLeader);
    Expression teamLeaderAddress = teamLeader.getAllowingNull("address");
    query.addJoinedAttribute(teamLeaderAddress);
    Expression teamMembers = query.getExpressionBuilder().anyOfAllowingNone("teamMembers");
    query.addJoinedAttribute(teamMembers);
    Expression teamMembersAddress = teamMembers.getAllowingNull("address");
    query.addJoinedAttribute(teamMembersAddress);
    Expression teamMembersPhones = teamMembers.anyOfAllowingNone("phoneNumbers");
    query.addJoinedAttribute(teamMembersPhones);

    String errorMsg = executeQueriesAndCompareResults(controlQuery, query);
    if (errorMsg.length() > 0) {
      fail(errorMsg);
    }
  }
  public void testEmployeeOuterJoinAddressPhoneProjectsTeamLeaderAddressTeamMembersPhones() {
    ReadAllQuery query = new ReadAllQuery();
    query.setReferenceClass(Employee.class);

    ReadAllQuery controlQuery = (ReadAllQuery) query.clone();

    // Note that without the following two lines address and phones are not read not for all
    // Employees:
    // once an Employee is built (without Address and Phones)
    // it's not going to be rebuilt (get Address and Phones) when it's
    // up again either as a teamLeader or teamMember.
    // That means that only Employees read first indirectly (either as teamLeaders or
    // teamMembers would've got Phones and Addresses).
    query.addJoinedAttribute(query.getExpressionBuilder().getAllowingNull("address"));
    query.addJoinedAttribute(query.getExpressionBuilder().anyOfAllowingNone("phoneNumbers"));

    Expression projects = query.getExpressionBuilder().anyOfAllowingNone("projects");
    query.addJoinedAttribute(projects);
    Expression teamLeader = projects.getAllowingNull("teamLeader");
    query.addJoinedAttribute(teamLeader);
    Expression teamLeaderAddress = teamLeader.getAllowingNull("address");
    query.addJoinedAttribute(teamLeaderAddress);
    Expression teamMembers = projects.anyOfAllowingNone("teamMembers");
    query.addJoinedAttribute(teamMembers);
    Expression teamMembersPhones = teamMembers.anyOfAllowingNone("phoneNumbers");
    query.addJoinedAttribute(teamMembersPhones);

    String errorMsg = executeQueriesAndCompareResults(controlQuery, query);
    if (errorMsg.length() > 0) {
      fail(errorMsg);
    }
  }
  public void testEmployeeJoinProjects() {
    ReadAllQuery query = new ReadAllQuery();
    query.setReferenceClass(Employee.class);

    ReadAllQuery controlQuery = (ReadAllQuery) query.clone();
    query.addJoinedAttribute(query.getExpressionBuilder().anyOf("projects"));

    String errorMsg = executeQueriesAndCompareResults(controlQuery, query);
    if (errorMsg.length() > 0) {
      fail(errorMsg);
    }
  }
  public void testProjectJoinTeamMembersOuterJoinAddress() {
    ReadAllQuery query = new ReadAllQuery();
    query.setReferenceClass(Project.class);

    ReadAllQuery controlQuery = (ReadAllQuery) query.clone();

    Expression teamMembers = query.getExpressionBuilder().anyOf("teamMembers");
    query.addJoinedAttribute(teamMembers);
    Expression teamMembersAddress = teamMembers.getAllowingNull("address");
    query.addJoinedAttribute(teamMembersAddress);

    String errorMsg = executeQueriesAndCompareResults(controlQuery, query);
    if (errorMsg.length() > 0) {
      fail(errorMsg);
    }
  }
  public void testProblemReporterProjectJoinTeamMembersJoinAddress() {
    ReadAllQuery query = new ReadAllQuery();
    query.setReferenceClass(Project.class);
    query.setSelectionCriteria(query.getExpressionBuilder().get("name").equal("Problem Reporter"));

    ReadAllQuery controlQuery = (ReadAllQuery) query.clone();

    Expression teamMembers = query.getExpressionBuilder().anyOf("teamMembers");
    query.addJoinedAttribute(teamMembers);
    Expression teamMembersAddress = teamMembers.get("address");
    query.addJoinedAttribute(teamMembersAddress);

    String errorMsg = executeQueriesAndCompareResults(controlQuery, query);
    if (errorMsg.length() > 0) {
      fail(errorMsg);
    }
  }
  public void testProjectJoinTeamLeaderJoinAddressWhereTeamLeaderNotNull() {
    ReadAllQuery query = new ReadAllQuery();
    query.setReferenceClass(Project.class);
    Expression teamLeader = query.getExpressionBuilder().get("teamLeader");
    query.setSelectionCriteria(teamLeader.notNull());

    ReadAllQuery controlQuery = (ReadAllQuery) query.clone();

    query.addJoinedAttribute(teamLeader);
    Expression teamLeaderAddress = teamLeader.get("address");
    query.addJoinedAttribute(teamLeaderAddress);

    String errorMsg = executeQueriesAndCompareResults(controlQuery, query);
    if (errorMsg.length() > 0) {
      fail(errorMsg);
    }
  }
  public void testEmployeeJoinProjectsJoinTeamLeaderJoinAddressWhereManagerIsNull() {
    ReadAllQuery query = new ReadAllQuery();
    query.setReferenceClass(Employee.class);
    query.setSelectionCriteria(query.getExpressionBuilder().get("manager").isNull());

    ReadAllQuery controlQuery = (ReadAllQuery) query.clone();
    Expression projects = query.getExpressionBuilder().anyOf("projects");
    query.addJoinedAttribute(projects);
    Expression teamLeader = projects.get("teamLeader");
    query.addJoinedAttribute(teamLeader);
    Expression teamLeaderAddress = teamLeader.get("address");
    query.addJoinedAttribute(teamLeaderAddress);

    String errorMsg = executeQueriesAndCompareResults(controlQuery, query);
    if (errorMsg.length() > 0) {
      fail(errorMsg);
    }
  }
    public void test() {
      ReadAllQuery query = new ReadAllQuery();
      query.setReferenceClass(Employee.class);
      setSelectionCriteria(query);

      ReadAllQuery controlQuery = (ReadAllQuery) query.clone();

      Expression employees = query.getExpressionBuilder().anyOf("managedEmployees");
      query.addJoinedAttribute(employees);
      Expression phones = employees.anyOf("phoneNumbers");
      query.addJoinedAttribute(phones);

      String errorMsg =
          JoinedAttributeTestHelper.executeQueriesAndCompareResults(
              controlQuery, query, (AbstractSession) getSession());
      if (errorMsg.length() > 0) {
        throw new TestErrorException(errorMsg);
      }
    }
  public void testEmployeeJoinManagerAddressOuterJoinManagerAddress() {
    ReadAllQuery query = new ReadAllQuery();
    query.setReferenceClass(Employee.class);
    query.setSelectionCriteria(
        query
            .getExpressionBuilder()
            .get("lastName")
            .equal("Way")
            .or(query.getExpressionBuilder().get("lastName").equal("Jones")));

    ReadAllQuery controlQuery = (ReadAllQuery) query.clone();
    Expression manager = query.getExpressionBuilder().get("manager");
    query.addJoinedAttribute(manager);
    query.addJoinedAttribute(manager.get("address"));
    Expression managersManager = manager.getAllowingNull("manager");
    query.addJoinedAttribute(managersManager);

    query.addJoinedAttribute(managersManager.get("address"));

    String errorMsg = executeQueriesAndCompareResults(controlQuery, query);
    if (errorMsg.length() > 0) {
      fail(errorMsg);
    }
  }
    public void test() {
      // clear cache
      getSession().getIdentityMapAccessor().initializeAllIdentityMaps();
      // create batch read query, set its selectionCriteria
      ReadAllQuery query = new ReadAllQuery(Employee.class);
      setSelectionCriteria(query);
      // before adding batch read attributes clone the query to create control query
      ReadAllQuery controlQuery = (ReadAllQuery) query.clone();
      // add batch read attributes
      Expression managedEmployees = query.getExpressionBuilder().get("managedEmployees");
      Expression managedEmployeesPhoneNumbers = managedEmployees.get("phoneNumbers");
      query.addBatchReadAttribute(managedEmployeesPhoneNumbers);
      // execute the query
      List employees = (List) getSession().executeQuery(query);
      if (employees.isEmpty()) {
        throw new TestProblemException("No Employees were read");
      }
      // need to instantiate only a single Phone on a single managed Employee to trigger sql that
      // reads data from the db for all.
      // still need to trigger all the indirections - but (except the first one) they are not
      // accessing the db
      // (the data is already cached in the value holders).
      printDebug("Trigger batch reading results");
      boolean isConnected = true;
      for (int i = 0; i < employees.size(); i++) {
        Employee manager = (Employee) employees.get(i);
        if (!manager.getManagedEmployees().isEmpty()) {
          printDebug("Manager = " + manager);
          for (int j = 0; j < manager.getManagedEmployees().size(); j++) {
            Employee emp = (Employee) manager.getManagedEmployees().get(j);
            printDebug("     " + emp);
            for (int k = 0; k < emp.getPhoneNumbers().size(); k++) {
              if (isConnected) {
                // need to instantiate only a single Phone on a single managed Employee to trigger
                // sql that reads data from the db for all.
                // to ensure that no other sql is issued close connection.
                ((AbstractSession) getSession()).getAccessor().closeConnection();
                isConnected = false;
              }
              PhoneNumber phone = (PhoneNumber) emp.getPhoneNumbers().get(k);
              printDebug("          " + phone);
            }
          }
        } else {
          printDebug(manager.toString());
        }
      }
      if (!isConnected) {
        // reconnect connection
        ((AbstractSession) getSession())
            .getAccessor()
            .reestablishConnection((AbstractSession) getSession());
      }
      printDebug("");

      // obtain control results
      // clear cache
      getSession().getIdentityMapAccessor().initializeAllIdentityMaps();
      // execute control query
      List controlEmployees = (List) getSession().executeQuery(controlQuery);
      // instantiate all value holders that the batch query expected to instantiate
      printDebug("Trigger control results");
      for (int i = 0; i < controlEmployees.size(); i++) {
        Employee manager = (Employee) controlEmployees.get(i);
        if (!manager.getManagedEmployees().isEmpty()) {
          printDebug("Manager = " + manager);
          for (int j = 0; j < manager.getManagedEmployees().size(); j++) {
            Employee emp = (Employee) manager.getManagedEmployees().get(j);
            printDebug("     " + emp);
            for (int k = 0; k < emp.getPhoneNumbers().size(); k++) {
              PhoneNumber phone = (PhoneNumber) emp.getPhoneNumbers().get(k);
              printDebug("          " + phone);
            }
          }
        } else {
          printDebug(manager.toString());
        }
      }

      // compare results
      String errorMsg =
          JoinedAttributeTestHelper.compareCollections(
              employees,
              controlEmployees,
              getSession().getClassDescriptor(Employee.class),
              ((AbstractSession) getSession()));
      if (errorMsg.length() > 0) {
        throw new TestErrorException(errorMsg);
      }
    }