Back to Devexpress

Relationships Between Objects

xpo-2041-create-a-data-model-relationships-between-objects.md

latest33.2 KB
Original Source

Relationships Between Objects

  • Oct 15, 2025
  • 22 minutes to read

XPO supports three types of relationships between objects. The type of a relationship that is created depends upon how related objects are defined.

  • One-to-Many Relationships
  • One-to-One Relationships
  • Many-to-Many Relationships

One-to-Many Relationships

A one-to-many relationship is the most common type of relationship. In this relationship, a persistent object of type A can have many associated objects of type B , but an object of type B can have only one associated object of type A.

For example, orders can be associated with a specific customer by creating a relationship between the Orders property in the Customer object (the primary key) and the Customer property in the Order object (the foreign key). As a result, each customer can have multiple orders.

The data model can be defined as shown below.

csharp
public class Customer : XPObject {
    public string ContactName {
        get { return fContactName; }
        set { SetPropertyValue(nameof(ContactName), ref fContactName, value); }
    }
    string fContactName;

    public string Phone {
        get { return fPhone; }
        set { SetPropertyValue(nameof(Phone), ref fPhone, value); }
    }
    string fPhone;

    // ...
    // Apply the Association attribute to mark the Orders property 
    // as the "many" end of the Customer-Orders association.
    [Association]
    public XPCollection<Order> Orders { 
        get { return GetCollection<Order>(nameof(Orders)); }
    }
}

public class Order : XPObject {
    public string ProductName {
        get { return fProductName; }
        set { SetPropertyValue(nameof(ProductName), ref fProductName, value); }
    }
    string fProductName;

    public DateTime OrderDate {
        get { return fOrderDate; }
        set { SetPropertyValue(nameof(OrderDate), ref fOrderDate, value); }
    }
    DateTime fOrderDate;

    // ...
    // Apply the Association attribute to mark the Customer property 
    // as the "one" end of the Customer-Orders association.
    [Association]
    public Customer Customer {
        get { return fCustomer; }
        set { SetPropertyValue(nameof(Customer), ref fCustomer, value); }
    }
    Customer fCustomer;

}
vb
Public Class Customer
    Inherits XPObject
    Public Property Name() As String
        Get
            Return fName
        End Get
        Set(ByVal value as String)
            SetPropertyValue(NameOf(Name), fName, value)
        End Set
    End Property
    Private fName As String

    Public Property Phone() As String
        Get
            Return fPhone
        End Get
        Set(ByVal value as String)
            SetPropertyValue(NameOf(Phone), fPhone, value)
        End Set
    End Property
    Private fPhone As String

    ' ...
    ' Apply the Association attribute to mark the Orders property 
    ' as the "many" end of the Customer-Orders association.
    <Association> _
    Public ReadOnly Property Orders() As XPCollection(Of Order)
        Get
            Return GetCollection(Of Order)(NameOf(Orders))
        End Get
    End Property
End Class

Public Class Order
    Inherits XPObject
    Public Property ProductName() As String
        Get
            Return fProductName
        End Get
        Set(ByVal value as String)
            SetPropertyValue(NameOf(ProductName), fProductName, value)
        End Set
    End Property
    Private fProductName As String

    Public Property OrderDate() As DateTime
        Get
            Return fOrderDate
        End Get
        Set(ByVal value as DateTime)
            SetPropertyValue(NameOf(OrderDate), fOrderDate, value)
        End Set
    End Property
    Private fOrderDate As DateTime

    ' ...
    ' Apply the Association attribute to mark the Customer property 
    ' as the "one" end of the Customer-Orders association.
    <Association> _
    Public Property Customer() As Customer
        Get
            Return fCustomer
        End Get
        Set(ByVal value as Customer)
            SetPropertyValue(NameOf(Customer), fCustomer, value)
        End Set
    End Property
    Private fCustomer As Customer

End Class

Important

Do not modify the XPCollection property declaration demonstrated above. Manipulating the collection or introducing any additional settings within the declaration may cause unpredictable behavior.

Here, the Association attribute (AssociationAttribute) is applied to the Customer.Orders and Order.Customer properties to identify both ends of the association. When one object relates to other objects, the “many” end of the association must be defined by an XPCollection or XPCollection<T> class.

One-to-One Relationships

Let’s consider a simple example of a One-to-One relationship. Two classes form the relationship. They both contain properties that reference the other class. You need to write code within the property’s setter method to ensure the relationship’s integrity. When a property accepts a new object, you need to update the other end of the relationship.

The following example shows how you can implement this.

csharp
// Represents the Building class which refers to the building's owner.
public class Building : XPObject {
    Person owner = null;
    public Person Owner {
        get { return owner; }
        set {
            if(owner == value)
                return;

            // Store a reference to the former owner.
            Person prevOwner = owner;
            owner = value;

            if(IsLoading) return;

            // Remove an owner's reference to this building, if exists.
            if(prevOwner != null && prevOwner.House == this)
                prevOwner.House = null;

            // Specify that the building is a new owner's house.
            if(owner != null)
                owner.House = this;
            OnChanged(nameof(Owner));
        }
    }
}

// Represents the Person class which refers to the person's house.
public class Person : XPObject {
    Building house = null;
    public Building House {
        get { return house; }
        set {
            if(house == value)
                return;

            // Store a reference to the person's former house.
            Building prevHouse = house;
            house = value;

            if(IsLoading) return;

            // Remove a reference to the house's owner, if the person is its owner.
            if(prevHouse != null && prevHouse.Owner == this)
                prevHouse.Owner = null;

            // Specify the person as a new owner of the house.
            if(house != null)
                house.Owner = this;

            OnChanged(nameof(House));
        }
    }
}
vb
' Represents the Building class which refers to the building's owner.
Public Class Building : Inherits XPObject
    Dim _owner As Person = Nothing
    Public Property Owner() As Person
        Get
            Return _owner
        End Get
        Set(ByVal Value As Person)
            If _owner Is Value Then
                Return
            End If

            ' Store a reference to the former owner.
            Dim prevOwner As Person = _owner
            _owner = Value

            If IsLoading Then Return

            ' Remove an owner's reference to this building, if exists.
            If Not (prevOwner Is Nothing) AndAlso prevOwner.House Is Me Then
                prevOwner.House = Nothing
            End If

            ' Specify that the building is a new owner's house.
            If Not (_owner Is Nothing) Then
                _owner.House = Me
            End If

            OnChanged(NameOf(Owner))

        End Set
    End Property
End Class

' Represents the Person class which refers to the person's house.
Public Class Person : Inherits XPObject
    Dim _house As Building = Nothing
    Public Property House() As Building
        Get
            Return _house
        End Get
        Set(ByVal Value As Building)
            If _house Is Value Then
                Return
            End If

           ' Store a reference to the person's former house.
            Dim prevHouse As Building = _house
            _house = Value

            If IsLoading Then Return

            ' Remove a reference to the house's owner, if the person is its owner.
            If Not (prevHouse Is Nothing) AndAlso prevHouse.Owner Is Me Then
                prevHouse.Owner = Nothing
            End If

            ' Specify the person as a new owner of the house.
            If Not (_house Is Nothing) Then
                _house.Owner = Me
            End If

            OnChanged(NameOf(House))
        End Set
    End Property
End Class

Many-to-Many Relationships

In relational database systems, you can implement a many-to-many relationship between two tables as two one-to-many relationships to a third table (join, junction, or intermediate table). The following techniques allow you to implement a many-to-many relationship between two classes in XPO:

  • Use ManyToManyAliasAttribute to join many-to-many collection properties in an explicit one-to-many relationship. To create a one-to-many relationship, declare a third intermediate class (see Associative Entity).

This technique implies that you already have an intermediate table or you create it manually. For example, it might be useful when you use XPO to map to existing databases and the intermediate table has an integer key rather than a Guid key, or when it has a column to store additional data.

In the following code examples, the Location class can contain several Departments and every Department can contain several Locations.

Technique 1 (with a Custom Intermediate Object)

cs
using DevExpress.Xpo;
using System.Collections.Generic;
using System.ComponentModel;
// ...
// The Location class, which contains its name and information 
// about the departments at the location.
public class Location : XPObject {
    public Location(Session session) : base(session) { }
    public string Name {
        get { return fName; }
        set { SetPropertyValue(nameof(Name), ref fName, value); }
    }
    string fName;
    // Apply the Association attribute to mark the LocationDepartmentLinks property 
    // as the "many" end of the one-to-many association between Location and an intermediate object.
    [Association, Browsable(false)]
    public IList<LocationDepartmentLink> LocationDepartmentLinks {
        get {
            return GetList<LocationDepartmentLink>(nameof(LocationDepartmentLinks));
        }
    }
    // Apply the ManyToManyAlias attribute to mark the Departments property 
    // as the "many" end of the many-to-many association between Location and Department.
    [ManyToManyAlias(nameof(LocationDepartmentLinks), nameof(LocationDepartmentLink.LinkDepartment))]
    public IList<Department> Departments {
        get {
            return GetList<Department>(nameof(Departments));
        }
    }
}
// The Department class that contains its name 
// and references all the locations of the department's offices.
public class Department : XPObject {
    public Department(Session session) : base(session) { }
    public string Name {
        get { return fName; }
        set { SetPropertyValue(nameof(Name), ref fName, value); }
    }
    string fName;
    // Apply the Association attribute to mark the LocationDepartmentLinks property 
    // as the "many" end of the one-to-many association between Department and an intermediate object.
    [Association, Browsable(false)]
    public IList<LocationDepartmentLink> LocationDepartmentLinks {
        get {
            return GetList<LocationDepartmentLink>(nameof(LocationDepartmentLinks));
        }
    }
    // Apply the ManyToManyAlias attribute to mark the Locations property 
    // as the "many" end of the many-to-many association between Location and Department.
    [ManyToManyAlias(nameof(LocationDepartmentLinks), nameof(LocationDepartmentLink.LinkLocation))]
    public IList<Location> Locations {
        get {
            return GetList<Location>(nameof(Locations));
        }
    }
}
// The intermediate class that has links to Location and Department.
public class LocationDepartmentLink : XPObject {
    public LocationDepartmentLink(Session session) : base(session) { }
    private Location _LinkLocation;
    // Apply the Association attribute to mark the LinkLocation property 
    // as the "one" end of the one-to-many association between Location and an intermediate object.
    [Association]
    public Location LinkLocation {
        get { return _LinkLocation; }
        set { SetPropertyValue(nameof(LinkLocation), ref _LinkLocation, value); }
    }
    private Department _LinkDepartment;
    // Apply the Association attribute to mark the LinkDepartment property 
    // as the "one" end of the one-to-many association between Department and an intermediate object.
    [Association]
    public Department LinkDepartment {
        get { return _LinkDepartment; }
        set { SetPropertyValue(nameof(LinkDepartment), ref _LinkDepartment, value); }
    }
}
vb
Imports DevExpress.Xpo
Imports System.Collections.Generic
Imports System.ComponentModel
' ...
' The Location class, which contains its name and information 
' about the departments at the location.
Public Class Location
    Inherits XPObject
    Public Sub New(ByVal session As Session)
        MyBase.New(session)
    End Sub
    Public Property Name() As String
        Get
            Return fName
        End Get
        Set(ByVal value As String)
            SetPropertyValue(NameOf(Name), fName, value)
        End Set
    End Property
    Private fName As String
    ' Apply the Association attribute to mark the LocationDepartmentLinks property 
    ' as the "many" end of the one-to-many association between Location and an intermediate object.
    <Association, Browsable(False)>
    Public ReadOnly Property LocationDepartmentLinks() As IList(Of LocationDepartmentLink)
        Get
            Return GetList(Of LocationDepartmentLink)(NameOf(LocationDepartmentLinks))
        End Get
    End Property
    ' Apply the ManyToManyAlias attribute to mark the Departments property 
    ' as the "many" end of the many-to-many association between Location and Department.
    <ManyToManyAlias(nameof(LocationDepartmentLinks), nameof(LocationDepartmentLink.LinkDepartment))>
    Public ReadOnly Property Departments() As IList(Of Department)
        Get
            Return GetList(Of Department)(NameOf(Departments))
        End Get
    End Property
End Class
' The Department class, which contains its name 
' and references all the locations of the department's offices.
Public Class Department
    Inherits XPObject
    Public Sub New(ByVal session As Session)
        MyBase.New(session)
    End Sub
    Public Property Name() As String
        Get
            Return fName
        End Get
        Set(ByVal value As String)
            SetPropertyValue(NameOf(Name), fName, value)
        End Set
    End Property
    Private fName As String
    ' Apply the Association attribute to mark the LocationDepartmentLinks property 
    ' as the "many" end of the one-to-many association between Department and an intermediate object.
    <Association, Browsable(False)>
    Public ReadOnly Property LocationDepartmentLinks() As IList(Of LocationDepartmentLink)
        Get
            Return GetList(Of LocationDepartmentLink)(NameOf(LocationDepartmentLinks))
        End Get
    End Property
    ' Apply the ManyToManyAlias attribute to mark the Locations property 
    ' as the "many" end of the many-to-many association between Location and Department.
    <ManyToManyAlias(nameof(LocationDepartmentLinks), nameof(LocationDepartmentLink.LinkLocation))>
    Public ReadOnly Property Locations() As IList(Of Location)
        Get
            Return GetList(Of Location)(NameOf(Locations))
        End Get
    End Property
End Class
' The intermediate class that has links to Location and Department.
Public Class LocationDepartmentLink
    Inherits XPObject
    Public Sub New(ByVal session As Session)
        MyBase.New(session)
    End Sub
    Private _LinkLocation As Location
    ' Apply the Association attribute to mark the LinkLocation property 
    ' as the "one" end of the one-to-many association between Location and an intermediate object.
    <Association>
    Public Property LinkLocation() As Location
        Get
            Return _LinkLocation
        End Get
        Set(ByVal value As Location)
            SetPropertyValue(NameOf(LinkLocation), _LinkLocation, value)
        End Set
    End Property
    Private _LinkDepartment As Department
    ' Apply the Association attribute to mark the LinkDepartment property 
    ' as the "one" end of the one-to-many association between Department and an intermediate object.
    <Association>
    Public Property LinkDepartment() As Department
        Get
            Return _LinkDepartment
        End Get
        Set(ByVal value As Department)
            SetPropertyValue(NameOf(LinkDepartment), _LinkDepartment, value)
        End Set
    End Property
End Class

Technique 2 (with an Autogenerated Intermediate Object)

csharp
// Represents the Location class that contains its name and information 
// about the departments at the location.
public class Location: XPObject {
    public Location(Session session) : base(session) { }
    public string Name {
        get { return fName; }
        set { SetPropertyValue(nameof(Name), ref fName, value); }
    }
    string fName;

    // Apply the Association attribute to mark the Departments property 
    // as the many end of the LocationsDepartments association.
    [Association("LocationsDepartments")]
    public XPCollection<Department> Departments { 
        get { return GetCollection<Department>(nameof(Departments)); }
    }
}

// Represents the Department class that contains its name 
// and references all the locations of the department's offices.
public class Department: XPObject {
    public Department(Session session) : base(session) { }
    public string Name {
        get { return fName; }
        set { SetPropertyValue(nameof(Name), ref fName, value); }
    }
    string fName;

    // Apply the Association attribute to mark the Locations property 
    // as the many end of the LocationsDepartments association.
    [Association("LocationsDepartments")]
    public XPCollection<Location> Locations { 
        get { return GetCollection<Location>(nameof(Locations)); }
    }
}
vb
' Represents the Location class that contains its name and information 
' about the departments at the location.
Public Class Location : Inherits XPObject
    Public Sub New(ByVal session As Session)
        MyBase.New(session)
    End Sub
    Public Property Name() As String
        Get
            Return fName
        End Get
        Set(ByVal value as String)
            SetPropertyValue(NameOf(Name), fName, value)
        End Set
    End Property
    Private fName As String

    ' Apply the Association attribute to mark the Department's property 
    ' as the many end of the LocationsDepartments association.
    <Association("LocationsDepartments")> _
    Public ReadOnly Property Departments() As XPCollection(Of Department)
        Get
            Return GetCollection(Of Department)(NameOf(Departments))
        End Get
    End Property
End Class

' Represents the Department class that contains its name 
' and references all the locations of the department's offices.
Public Class Department : Inherits XPObject
    Public Sub New(ByVal session As Session)
        MyBase.New(session)
    End Sub
    Public Property Name() As String
        Get
            Return fName
        End Get
        Set(ByVal value as String)
            SetPropertyValue(NameOf(Name), fName, value)
        End Set
    End Property
    Private fName As String

    ' Apply the Association attribute to mark the Location's property 
    ' as the many end of the LocationsDepartments association.
    <Association("LocationsDepartments")> _
    Public ReadOnly Property Locations() As XPCollection(Of Location)
        Get
            Return GetCollection(Of Location)(NameOf(Locations))
        End Get
    End Property
End Class

The name of the intermediate table coincides with the association name specified in the Association attribute parameter when UseAssociationNameAsIntermediateTableName is set to true.

Note

  • This technique supports XPCollection<T> only.

  • Do not modify the XPCollection property declaration demonstrated above. Manipulating the collection or introducing any additional settings within the declaration may cause unpredictable behavior.

  • When you add an object to a collection involved in a many-to-many relationship, XPO automatically loads a collection on the other side of the relationship. This behavior may cause performance or memory issues if the second collection contains a large number of objects.

Create Demo Data

The following code demonstrates how you can create demo data for both techniques:

csharp
using DevExpress.Xpo;
// ...
public partial class Form1 : Form {
    UnitOfWork uw;
    public Form1() {
        InitializeComponent();
        uw = new UnitOfWork();
        CreateData(uw);
    }
    private void CreateData(UnitOfWork uw) {
        Department dep = new Department(uw);
        dep.Name = "Department A";
        Location loc = new Location(uw);
        loc.Name = "USA";
        dep.Locations.Add(loc);
        loc = new Location(uw);
        loc.Name = "UK";
        dep.Locations.Add(loc);
        uw.CommitChanges();
    }
}

Self-Referencing Relationship

A self-referencing relationship allows an object’s property to point to another object of the same type.

The following code snippet demonstrates how to create a hierarchical structure where an employee reports to a manager (who is also an employee):

csharp
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Xpo;

[DefaultClassOptions]
public class Employee : BaseObject {
    public Employee(Session session)
        : base(session) {
    }
    public override void AfterConstruction() {
        base.AfterConstruction();
    }
    string _firstName;
    public string FirstName {
        get {
            return _firstName;
        }
        set {
            SetPropertyValue(nameof(FirstName), ref _firstName, value);
        }
    }

    [Association]
    public XPCollection<Employee> Workers {
        get {
            return GetCollection<Employee>(nameof(Workers));
        }
    }
    Employee _manager;
    [Association]
    public Employee Manager {
        get {
            return _manager;
        }
        set {
            SetPropertyValue(nameof(Manager), ref _manager, value);
        }
    }
}

Association Attribute Specifics

The AssociationAttribute takes the following arguments.

  • The type of an object being linked to.

  • The name of the association.

Create and Persist Association Objects in Code

Define a One-to-Many Association

Create the Customer object that has the Name and Age properties, and the Order object that has the ProductName and OrderDate properties (for details, see Create a Business Model in the XPO Data Model Designer).

The Customer and Order objects must be connected with a one-to-many relationship since each customer can have multiple orders. Add the Customer property of the Customer type to the Order persistent class. This property will represent the “one” part of the association.

Next, focus the AggregationRelationship toolbox item and draw a line from Customer to Order.

Alternatively, you can define an association in code. To do this, the AssociationAttribute is used on both ends of an association. This attribute specifies the name of the relationship and points to the corresponding properties. The association name specified via the AssociationAttribute.Name parameter should match the name used at the other end of the association. The Orders property, which represents the ‘many’ side of a relationship, should be of the XPCollection type. It’s value should be calculated via the XPBaseObject.GetCollection method that returns all persistent objects related to the property.

csharp
public class Order : XPObject {
   // ...
   private Customer _customer;
   [Association("Customer-Orders")]
   public Customer Customer {
      get { return _customer; }
      set { SetPropertyValue(nameof(Customer), ref _customer, value); }
   }
}
public class Customer : XPObject {
   // ...
   [Association("Customer-Orders")]
   public XPCollection<Order> Orders { get { return GetCollection<Order>(nameof(Orders)); } }
}
vb
Public Class Order
   Inherits XPObject
   ' ...
   Private _customer As Customer
   <Association("Customer-Orders")> _
   Public Property Customer() As Customer
      Get
          Return _customer
      End Get
      Set(ByVal value As Customer)
         SetPropertyValue(NameOf(Customer), _customer, value)
      End Set
   End Property
End Class

Public Class Customer
   Inherits XPObject
   ' ...
   <Association("Customer-Orders")> _
   Public ReadOnly Property Orders() As XPCollection(Of Order)
      Get
         Return GetCollection(Of Order)(NameOf(Orders))
      End Get
   End Property
End Class

Add Persistent Objects Explicitly

Create Customer objects and populate the Customer.Orders collections with Orders.

csharp
if (xpCollection1.Count == 0) {
    Customer customer1 = new Customer(session1);
    customer1.Name = "John";
    customer1.Age = 21;
    customer1.Orders.Add(new Order(session1) { 
        ProductName = "Chai", 
        OrderDate = new DateTime(2013, 3, 11) 
    });
    customer1.Orders.Add(new Order(session1) {
        ProductName = "Konbu",
        OrderDate = new DateTime(2013, 1, 23)
    });
    customer1.Save();
    xpCollection1.Add(customer1);

    Customer customer2 = new Customer(session1);
    customer2.Name = "Bob";
    customer2.Age = 37;
    customer2.Orders.Add(new Order(session1) {
        ProductName = "Queso Cabrales",
        OrderDate = new DateTime(2013, 2, 9)
    });
    customer2.Save();
    xpCollection1.Add(customer2);
}
vb
If xpCollection1.Count = 0 Then
    Dim customer1 As New Customer(session1)
    customer1.Name = "John"
    customer1.Age = 21
    customer1.Orders.Add(New Order(session1) With {
        .ProductName = "Chai",
        .OrderDate = New Date(2013, 3, 11)
    })
    customer1.Orders.Add(New Order(session1) With {
        .ProductName = "Konbu",
        .OrderDate = New Date(2013, 1, 23)
    })
    customer1.Save()
    xpCollection1.Add(customer1)

    Dim customer2 As New Customer(session1)
    customer2.Name = "Bob"
    customer2.Age = 37
    customer2.Orders.Add(New Order(session1) With {
        .ProductName = "Queso Cabrales",
        .OrderDate = New Date(2013, 2, 9)
    })
    customer2.Save()
    xpCollection1.Add(customer2)
End If

Note

The Save method checks whether the database contains the Customer and Order tables (these names match the names of the XP Objects being saved). If no such tables are found, they are created and relationships are established based on the declarations of the XP Objects.

Use the Back Master Reference Property

You can assign the Customer object to the Order object’s Customer property. The new Order objects automatically appear in the Customer object’s Orders collection.

csharp
if(xpCollection1.Count == 0) { 
    Customer customer1 = new Customer(session1); 
    customer1.Name = "John"; 
    customer1.Age = 21; 
    new Order(session1) { 
        ProductName = "Chai", 
        OrderDate = new DateTime(2013, 3, 11), 
        Customer = customer1 
    }; 
    new Order(session1) { 
        ProductName = "Konbu", 
        OrderDate = new DateTime(2013, 1, 23), 
        Customer = customer1 
    }; 
    customer1.Save(); 
    xpCollection1.Add(customer1); 

    Customer customer2 = new Customer(session1); 
    customer2.Name = "Bob"; 
    customer2.Age = 37; 
    new Order(session1) { 
        ProductName = "Queso Cabrales", 
        OrderDate = new DateTime(2013, 2, 9), 
        Customer = customer2 
    }; 
    customer2.Save(); 
    xpCollection1.Add(customer2); 
}
vb
If xpCollection1.Count = 0 Then
    Dim customer1 As New Customer(session1)
    customer1.Name = "John"
    customer1.Age = 21
    Call New Order(session1) With {
        .ProductName = "Chai",
        .OrderDate = New Date(2013, 3, 11),
        .Customer = customer1
    }
    Call New Order(session1) With {
        .ProductName = "Konbu",
        .OrderDate = New Date(2013, 1, 23),
        .Customer = customer1
    }
    customer1.Save()
    xpCollection1.Add(customer1)

    Dim customer2 As New Customer(session1)
    customer2.Name = "Bob"
    customer2.Age = 37
    Call New Order(session1) With {
        .ProductName = "Queso Cabrales",
        .OrderDate = New Date(2013, 2, 9),
        .Customer = customer2
    }
    customer2.Save()
    xpCollection1.Add(customer2)
End If

If you can access only the object’s ID, get the object’s instance from the current Session.

csharp
//... 
int customer1Id = 15; 
Customer customer1 = session1.GetObjectByKey<Customer>(customer1Id); 
new Order(session1) { 
    ProductName = "Chai", 
    OrderDate = new DateTime(2013, 3, 11), 
    Customer = customer1 
}; 
//...
vb
'... 
Dim customer1Id As Integer = 15
Dim customer1 As Customer = session1.GetObjectByKey(Of Customer)(customer1Id)
Call New Order(session1) With {
    .ProductName = "Chai",
    .OrderDate = New Date(2013, 3, 11),
    .Customer = customer1
}
'...

Aggregate Relationships (Cascade Delete)

To indicate an aggregate one-to-many relationship, add the Aggregated attribute (AggregatedAttribute) to the collection that specifies the association’s “many” end. This indicates that the collection’s objects are considered part of the associated object.

csharp
public class Customer : XPObject {
    // ...
    [Association, Aggregated]
    public XPCollection<Order> Orders {
        get { return GetCollection<Order>(nameof(Orders)); }
    }
}
vb
Public Class Customer
    Inherits XPObject
    ' ...
    <Association, Aggregated> _
    Public ReadOnly Property Orders() As XPCollection(Of Order)
        Get
            Return GetCollection(Of Order)(NameOf(Orders))
        End Get
    End Property
End Class

Since it makes no sense to keep orders when the associated Customer object is deleted, the Aggregated attribute is applied to the Customer.Orders property. When a Customer object is deleted, the associated Order objects are deleted as well.

Note

If you have DevExpress WinForms components installed, you can try the functionality described here in the Object Relational Mapping | One to Many Relations section of the XPO Tutorials demo (C:\Users\Public\Documents\DevExpress Demos 25.2\Components\WinForms\Bin\XpoTutorials.exe).

You can also apply the Aggreagated attribute to a reference property as demonstrated in the following help topic: How to: Create an Aggregated Object.

Member Table

Online Knowledge Base

See Also

XPO Templates

AssociationAttribute