Skip to main content

Free Joins

  • 3 minutes to read

With XPO, you can build criteria based on persistent objects that are not directly related (don’t have explicitly defined associations) using Free Joins. In essence, XPO allows you to join any persistent objects on a condition, calculate aggregate functions against matching objects using their properties, and return aggregate values as the result of joining. To accomplish this, use JoinOperands in your criteria.

Options for creating the JoinOperand include:

  • The CriteriaOperator.Parse method.

    The general format of the method’s criteria string parameter is: [<JoinTypeName>][JoinCondition]

    Here, JoinTypeName represents the JoinOperand.JoinTypeName property value, while JoinCondition is a string representation of the CriteriaOperator equivalent of the join condition.

    To indicate properties of the parent object within the join condition, prefix them with a caret and dot (‘^.‘), as shown below:

    [<JoinTypeName>][[^.ParentObjectProperty] = [JoinedObjectProperty]]

    The following code snippet demonstrates how to retrieve employees that closed more than 50 orders.

    CriteriaOperator criteria = 
        CriteriaOperator.Parse("[<Orders>][^.EmployeeID = EmployeeID].Count() > 50");
    XPCollection<Employee> employees = new XPCollection<Employee>(session, criteria);
  • The JoinOperand constructors.

    You can use specific constructors to create the JoinOperand, and initialize it with join and aggregate settings via corresponding constructor parameters.

    CriteriaOperator joinCriteria = 
        new OperandProperty("^.EmployeeID") == new OperandProperty("EmployeeID");
    JoinOperand joinOperand = 
        new JoinOperand("Orders", joinCriteria, Aggregate.Count, new OperandProperty("EmployeeID"));
    BinaryOperator criteria = 
        new BinaryOperator(joinOperand, new OperandValue(50), BinaryOperatorType.Greater);
    XPCollection<Employee> employees = 
        new XPCollection<Employee>(session, criteria);

    Note that if a criteria contains types from different namespaces, the JoinOperand.JoinTypeName propery 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"
  • The Join operation in LINQ to XPO.

    The syntax is the same as the syntax of group joins (the JoinGroup method) in LINQ.

    XPQuery<Employee> employees = new XPQuery<Employee>(session);
    XPQuery<Orders> orders = new XPQuery<Orders>(session);
    var list = from e in employees
               join o in orders on e.EmployeeID equals o.EmployeeID.EmployeeID into query
               where query.Count() > 50
               select e
See Also