Skip to main content

JoinOperand Class

An operator that joins persistent objects on a specified condition, and calculates aggregate functions against matching objects.

Namespace: DevExpress.Data.Filtering

Assembly: DevExpress.Data.v23.2.dll

NuGet Package: DevExpress.Data


public class JoinOperand :


The JoinOperand works only with eXpress Persistent Objects. Use the JoinOperand to build criteria and calculate aggregate functions using the properties of persistent objects without explicitly defined associations. Persistent objects applied to the current JoinOperand are called parent objects for the join. To specify the type of persistent objects to be joined with parent objects, use the JoinOperand.JoinTypeName property.

To access parent object properties in a join condition, use the Parent Relating Operator.

The JoinOperand does the following:

This example demonstrates how to load all employees who can issue refunds (the Employee and User table should have a one-to-one relationship).

using DevExpress.Xpo;
using DevExpress.Data.Filtering;
// ..

/* create via CriteriaOperator.Parse */
// string expr = "[<User>][[Oid] = [^.Oid] && [Permissions][[Action] = ?]]";
// CriteriaOperator filter = CriteriaOperator.Parse(expr, "Issue Refunds");

/* create via constructor */
CriteriaOperator joinCondition = new OperandProperty(nameof(Employee.Oid)) == new OperandProperty($"^.{nameof(User.Oid)}");
CriteriaOperator filterClause = new ContainsOperator(
    collectionProperty: new OperandProperty(nameof(User.Permissions)),
    condition: new OperandProperty(nameof(Permission.Action)) == new OperandValue("Issue Refunds")
CriteriaOperator filter = new JoinOperand(
        joinTypeName: nameof(User),
        condition: joinCondition & filterClause

XPCollection<Employee> employees = new XPCollection<Employee>(session, filter);

If a criteria contains types from different namespaces, the JoinOperand.JoinTypeName property should contain the full type name with its namespace, for example, as follows:

"[<Application.SomeNamespace.Customers>][^.GroupID = GroupID].Count() > 1 
and  [<Application.OtherNamespace.Orders>][^.EmployeeID = EmployeeID].Count() > 50"

Refer to the Free Joins help topic for more information on how to use the JoinOperand.


  • To improve performance, we recommend that you not use the JoinOperand when filtering or sorting the XPCollection on the client side since this increases the number of queries sent to the server.
  • JoinOperand may produce null instead of zero for an empty collection on a server side.


You can find examples in the following article: Build Criteria - Cheat Sheet.


See Also