Enhancing Tasklists with Business Data

Allow users to filter their tasks by relevant business data. Display this data right inside the task list and not just when selecting a task form. To achieve this with acceptable performance, select the implementation approach appropriate for your needs.
Enhancing Tasklists with Business Data

Selecting an Implementation Approach

To enhance your tasklist with business data, select the implementation approach appropriate for your needs.

Camunda Process Variables

Custom Queries

Custom
Process or Task "InfoEntity"

Camunda Native Query API

Custom
MyBatis Mapping

Use simple process or task variables to store business data with tasks, often as an additional copy.

Use a native query to enhance query performance when retrieving tasks filtered by business data.

Use a custom database mapping to speed up retrieval of task data combined with business data.

Use a custom database entity to store business data optimized for search and display.

Filter with Business Data as Simple Process Variables

Filter with Business Data in Domain Database

Display Business Data from Domain Database

(only via "copy as process variable")

(only via "copy as process variable")

Development Effort

out-of-the-box

low

high

high

No Dependency on Camunda Internals

(take care not to use hard coded table names)

(take care not to use hard coded table names)

Required Know-How

SQL

SQL, Apache MyBatis, Advanced Camunda

Depends (e.g. JPA or JDBC)

Scaling / Performance

Limited
(~ 5-10 criteria)

Medium (dep. on use case)

Medium (dep. on use case)

High (customized)

Out-of-the-box usage with Camunda Tasklist

Learn more

Learn more

Learn more

Learn more

Using Camunda Process/Task Variables

Using plain and simple process or task variables to store business data has the big advantage that you can use the out-of-the-box mechanisms. Plain and simple means to only use primary data types (e.g. String, Long, …​). Especially when using Camunda tasklist you can easily use process/task variables to

  • show custom business data right inside the list, or

  • use such variables for defining re-usable filters which narrow down your tasklist items to the ones matching:

process variables

Including derived or calculated values

In case you need dynamically calculated values or specific fields derived from complex datatypes/objects, you can achieve this by

  • using task variables as a kind of caching mechanism,

  • being filled by "calculating" the values using expression language

  • e.g. by means of an I/O Mapping of a User Task:

<task id="..." name="Create new payment">
  <extensionElements>
    <camunda:inputOutput>
      <camunda:inputParameter name="paymentSum">${invoice.calculateSum()}</camunda:inputParameter> (1)
      <camunda:inputParameter name="creditorId">${invoice.creditorId}</camunda:inputParameter> (2)
    </camunda:inputOutput>
  </extensionElements>
</task>
1 The total sum of the payment is calculated by calling a method on an invoice object and cached for search and display purposes.
2 The creditorId is copied into an own variable, so it can be used in filters or shown in the tasklist.

The disadvantage of using process or task variables is that this mechanism does not scale very well, as the process variables are stored in the generic Camunda database schema. This requires one row in the variable table for each variable, and all of them must be joined with the process instance table. The real limit is determined by the amount of data and the database used - but typically you cannot use more than 10 variables.

Using a special search variable

If you need variables only to search for tasks (but not to display attributes in the tasklist) you can use a simple workaround: Introduce one single process variable optimized for tasklist queries. Extract the attributes you need to filter your tasklist with and combine them to a single search string prepared to work with a SQL 'LIKE' query:

Variable Type Value

customerId

(Long)

4711

customerName

(String)

camunda

customerPlace

(String)

Berlin

searchString

(String)

customerId=4711#customerName=camunda#customerPlace=Berlin

When defining your Camunda tasklist filter, use the searchString variable and search in it by means of a 'LIKE' query.

Implementing Custom Queries

Using the Camunda Native Query API

When you need to filter your tasks by business data stored in your own tables, leverage the possibility to create native queries via the Camunda Java API. Native Queries are

  • expressed in SQL which is not limited to the Camunda Tables. However

  • the result is still mapped to the Camunda Task entity, so you do not have to dive into Apache MyBatis (the persistence framework used within Camunda).

This means you cannot load data from your domain objects by native queries, you simply can express arbritrary WHERE clauses. Example:

List<Task> tasks = taskService.createNativeTaskQuery()
  .sql("SELECT * FROM #{taskTable} T"
     + "LEFT OUTER JOIN (select * from #{variablesTable} where NAME_= 'customerId') VAR_CUSTOMER"
     + "  ON VAR_CUSTOMER.EXECUTION_ID_ = T.EXECUTION_ID_"
     + "LEFT OUTER JOIN CUSTOMER " (1)
     + "  ON CUSTOMER.ID_ = VAR_CUSTOMER.LONG_"
     + "WHERE CUSTOMER.COMPANY = #{companyName}")
           .parameter("companyName", "camunda")
  .parameter("taskTable", managementService.getTableName(Task.class)) (2)
  .parameter("variablesTable", managementService.getTableName(VariableInstance.class))
  .list();
1 Using native queries allows you to directly join Camunda tables with custom Business Data Tables (held in the same database) while still retrieving Task.class typed resultsets.
2 Make sure that you do not use hard coded table names to be less dependant on Camunda Internals. However, please note that the example still uses INTERNALAPI details, e.g. by using column names. Your queries or table/column name mappings would need to be adapted in case these internal details change.

Implementing a Custom MyBatis Mapping

In case you want to not just filter tasklists for business data, but also load custom data from domain objects in one query you can implement your own MyBatis mapping and call it via custom code.

Even if this is a very powerful mechanism, we normally do not recommend it, as you need to understand quite a bit about MyBatis. It will be hard to completely avoid dependencies on the Camunda database schema. The database schema is considered INTERNALAPI , hence this also might impose additional maintenance effort in your project for new Camunda versions.

You can find an example in this (unmaintaned and potentially out-of-date) code snippet.

Implementing a Custom Process/Task Info Entity

For maximal flexibiliy (and best performance possibilities), create a custom ProcessInstanceEntity and/or TaskEntity designed to filter tasklists and display business data.

Prefer a ProcessInstanceEntity over a TaskEntity as long as the business data you need is quite similar in between the different user tasks of a process definition. This way you avoid unnecessary database operations. If this is not the case you need to go for the TaskEntity as shown in the following example.
processinstanceinfo

In this entity, combine the Camunda task.id with all your business attributes as separate columns. This allows to query for and display tasks without or with a minimum of SQL JOINs. Consider to use your entity now as a single source for displaying tasklists to your users - hence circumventing the Camunda TaskService Query API for that purpose completely.

Using this approach requires to synchronize your entity with the Camunda state.

If you target a TaskInfoEntity:

  • Create it via a TaskListener

  • Delete it via a Tasklistener

If you target a ProcessInstanceInfoEntity:

  • Create a new instance by an ExecutionListener on the process instance start event.

The process instance id might not yet be known at this time. So either you create your own id and set it as a process variable (to SQL "join" on this later), or you can add a safe point (see Understanding Transactions in Processes) before the listener triggers to make sure the process instance was committed to the database.
  • Decide when you have to update information in the entity, this depends on various factors (like amount of data, frequency of changes, way of changing data, …​).

No guarantee - The statements made in this publication are recommendations based on the practical experience of the authors. They are not part of Camunda’s official product documentation. Camunda cannot accept any responsibility for the accuracy or timeliness of the statements made. If examples of source code are shown, a total absence of errors in the provided source code cannot be guaranteed. Liability for any damage resulting from the application of the recommendations presented here, is excluded.

Copyright © Camunda Services GmbH - All rights reserved. The disclosure of the information presented here is only permitted with written consent of Camunda Services GmbH.