Java Collection mit SQL abfragen - ist das machbar?

von

In einem aktuellen Projekt standen wir vor der Herausforderung, ein komplexes Dashboard zu implementieren, das unzählige SQL-Abfragen - mit einer gewissen Komplexität - gegen die Datenbank durchführte.

Will man den zurückgegebenen SQL-Resultset am Ende eventuell in Java weiter filtern, um die SQL-Abfrage nicht noch komplexer (oder langsamer) werden zu lassen, so entsteht meist unleserlicher Quellcode, verursacht durch den Einsatz von vielen bedingten Anweisungen und Verzweigungen.

Bei einer Internetrecherche sind wir schließlich auf Github auf das Projekt: CQEngine - Collection Query Engine aufmerksam geworden. Mit diesem Framework ist es machbar, SQL-analoge Konstrukte zum Abfragen von Collections zu implementieren.

Folgende Zeilen zeigen, wie man mit dem Framework CQEngine eine Abfrage implementiert:

...
public static double calculateProcessingTime(
      IndexedCollection<ProcessingTimeDTO> processingTimes,
      String[] dep_numbers,
      ArticleType article_type,
      Integer year,
      Integer month) {

    Set<String> distinctOrders =
        processingTimes
            .retrieve(
                and(
                    in(ProcessingTimeDTO.DEP_NUMBER, Constants.DEPARTMENT_RELEASE_PRODUCTION),
                    equal(ProcessingTimeDTO.YEAR, year),
                    equal(ProcessingTimeDTO.MONTH, month),
                    equal(ProcessingTimeDTO.ARTICLE_TYPE, article_type.toString())))
            .stream()
            .map(ProcessingTimeDTO::getOrder_number)
            .collect(Collectors.toSet());
...

Die Attribute, die für die SQL-Abfragen auf den Java Collections benutz werden sollen müssen folgendermaßen angeben werden:

...
public static final SimpleAttribute<ProcessingTimeDTO, String> ORDER_NUMBER =
      new SimpleAttribute<ProcessingTimeDTO, String>("order_number") {
        public String getValue(ProcessingTimeDTO ProcessingTimeDTO, QueryOptions queryOptions) {
          return ProcessingTimeDTO.order_number;
        }
      };

  public static final SimpleAttribute<ProcessingTimeDTO, String> ARTICLE_TYPE =
      new SimpleAttribute<ProcessingTimeDTO, String>("article_type") {
        public String getValue(ProcessingTimeDTO ProcessingTimeDTO, QueryOptions queryOptions) {
          return ProcessingTimeDTO.article_type;
        }
      };

  public static final SimpleAttribute<ProcessingTimeDTO, String> DEP_NUMBER =
      new SimpleAttribute<ProcessingTimeDTO, String>("dep_number") {
        public String getValue(ProcessingTimeDTO ProcessingTimeDTO, QueryOptions queryOptions) {
          return ProcessingTimeDTO.dep_number;
        }
      };

  public static final SimpleAttribute<ProcessingTimeDTO, Integer> YEAR =
      new SimpleAttribute<ProcessingTimeDTO, Integer>("year") {
        public Integer getValue(ProcessingTimeDTO ProcessingTimeDTO, QueryOptions queryOptions) {
          return ProcessingTimeDTO.year;
        }
      };

  public static final SimpleAttribute<ProcessingTimeDTO, Integer> MONTH =
      new SimpleAttribute<ProcessingTimeDTO, Integer>("month") {
        public Integer getValue(ProcessingTimeDTO ProcessingTimeDTO, QueryOptions queryOptions) {
          return ProcessingTimeDTO.month;
        }
      };
...

Fazit

In unserem Projekt waren wir von den Möglichkeiten der CQEngine angetan. Viel Spaß beim Ausprobieren.

Und bitte nicht vergessen, Indexes zu setzen, den erst diese ermöglichen hochperformante Abfragen.

...
 processingTimes.addIndex(NavigableIndex.onAttribute(ProcessingTimeDTO.ORDER_NUMBER));
 processingTimes.addIndex(NavigableIndex.onAttribute(ProcessingTimeDTO.ARTICLE_TYPE));
 processingTimes.addIndex(NavigableIndex.onAttribute(ProcessingTimeDTO.DEP_NUMBER));
 processingTimes.addIndex(NavigableIndex.onAttribute(ProcessingTimeDTO.MONTH));
 processingTimes.addIndex(NavigableIndex.onAttribute(ProcessingTimeDTO.YEAR));
...

Zurück