/**
   * Resolves a sublist of objects starting at <code>fromIndex</code> up to but not including <code>
   * toIndex</code>. Internally performs bound checking and trims indexes accordingly.
   */
  protected void resolveInterval(int fromIndex, int toIndex) {
    if (fromIndex >= toIndex) {
      return;
    }

    synchronized (elements) {
      if (elements.size() == 0) {
        return;
      }

      // perform bound checking
      if (fromIndex < 0) {
        fromIndex = 0;
      }

      if (toIndex > elements.size()) {
        toIndex = elements.size();
      }

      List<Expression> quals = new ArrayList<>(pageSize);
      List<Object> ids = new ArrayList<>(pageSize);
      for (int i = fromIndex; i < toIndex; i++) {
        Object object = elements.get(i);
        if (helper.unresolvedSuspect(object)) {
          quals.add(buildIdQualifier(object));
          ids.add(object);
        }
      }

      int qualsSize = quals.size();
      if (qualsSize == 0) {
        return;
      }

      // fetch the range of objects in fetchSize chunks
      boolean fetchesDataRows = internalQuery.isFetchingDataRows();
      List<Object> objects = new ArrayList<>(qualsSize);

      int fetchSize = maxFetchSize > 0 ? maxFetchSize : Integer.MAX_VALUE;

      int fetchEnd = Math.min(qualsSize, fetchSize);
      int fetchBegin = 0;
      while (fetchBegin < qualsSize) {
        SelectQuery<Object> query =
            new SelectQuery<>(
                rootEntity,
                ExpressionFactory.joinExp(Expression.OR, quals.subList(fetchBegin, fetchEnd)));

        query.setFetchingDataRows(fetchesDataRows);

        if (!query.isFetchingDataRows()) {
          query.setPrefetchTree(internalQuery.getPrefetchTree());
        }

        objects.addAll(dataContext.performQuery(query));
        fetchBegin = fetchEnd;
        fetchEnd += Math.min(fetchSize, qualsSize - fetchEnd);
      }

      // sanity check - database data may have changed
      checkPageResultConsistency(objects, ids);

      // replace ids in the list with objects
      Iterator it = objects.iterator();
      while (it.hasNext()) {
        helper.updateWithResolvedObjectInRange(it.next(), fromIndex, toIndex);
      }

      unfetchedObjects -= objects.size();
    }
  }