Back to Devexpress

How to: Link Classes Located in Different Assemblies

xpo-3235-examples-how-to-link-classes-located-in-different-assemblies.md

latest10.3 KB
Original Source

How to: Link Classes Located in Different Assemblies

  • Oct 06, 2022
  • 5 minutes to read

This topic describes how to implement relationships between XPO classes declared in different assemblies.

Data Model

The examples in this topic use the following data model:

Assembly: ClassLibrary1.dll

csharp
using DevExpress.Xpo;

namespace ClassLibrary1 {
    public class Order : XPObject {
        public Order(Session session) : base(session) { }

        private int orderNumber;
        public int OrderNumber {
            get { return orderNumber; }
            set { SetPropertyValue(nameof(OrderNumber), ref orderNumber, value); }
        }
    }
}
vb
Imports DevExpress.Xpo

Namespace ClassLibrary1
    Public Class Order
        Inherits XPObject

        Public Sub New(ByVal session As Session)
            MyBase.New(session)
        End Sub

        Private _orderNumber As Integer
        Public Property OrderNumber() As Integer
            Get
                Return _orderNumber
            End Get
            Set(ByVal value As Integer)
                SetPropertyValue(NameOf(OrderNumber), _orderNumber, value)
            End Set
        End Property
    End Class
End Namespace

Assembly: ClassLibrary2.dll

csharp
using DevExpress.Xpo;

namespace ClassLibrary2 {
    public class Customer : XPObject {
        public Customer(Session session) : base(session) { }

        private string fullName;
        public string FullName {
            get { return fullName; }
            set { SetPropertyValue(nameof(FullName), ref fullName, value); }
        }
    }
}
vb
Imports DevExpress.Xpo

Namespace ClassLibrary2
    Public Class Customer
        Inherits XPObject

        Public Sub New(ByVal session As Session)
            MyBase.New(session)
        End Sub

        Private _fullName As String
        Public Property FullName() As String
            Get
                Return _fullName
            End Get
            Set(ByVal value As String)
                SetPropertyValue(NameOf(FullName), _fullName, value)
            End Set
        End Property
    End Class
End Namespace

Derived Class

You can use XPO inheritance to implement relationships between classes from the current assembly (ClassLibrary2) and classes from an external class library (ClassLibrary1). Use this technique when the external library declares XPO classes without additional business logic. Applications that share this library should connect to different databases.

In this example, the CustomerOrder class inherits the Order class from another assembly. The Customer class has a collection of related CustomerOrder classes. In this case, an application should use the CustomerOrder class rather than the Order class to implement operations with orders:

Assembly: ClassLibrary2.dll

csharp
using DevExpress.Xpo;

namespace ClassLibrary2 {
    public class Customer : XPObject {
        public Customer(Session session) : base(session) { }
        //...
        [Association, Aggregated]
        public XPCollection<CustomerOrder> Orders {
            get { return GetCollection<CustomerOrder>(nameof(Orders)); }
        }
    }
    [MapInheritance(MapInheritanceType.ParentTable)]
    public class CustomerOrder : ClassLibrary1.Order {
        public CustomerOrder(Session session) : base(session) { }

        private Customer customer;
        [Association]
        public Customer Customer {
            get { return customer; }
            set { SetPropertyValue(nameof(Customer), ref customer, value); }
        }
    }
}
vb
Imports DevExpress.Xpo

Namespace ClassLibrary2
    Public Class Customer
        Inherits XPObject

        Public Sub New(ByVal session As Session)
            MyBase.New(session)
        End Sub
        '...
        <Association, Aggregated>
        Public ReadOnly Property Orders() As XPCollection(Of CustomerOrder)
            Get
                Return GetCollection(Of CustomerOrder)(NameOf(Orders))
            End Get
        End Property
    End Class

    <MapInheritance(MapInheritanceType.ParentTable)>
    Public Class CustomerOrder
        Inherits ClassLibrary1.Order

        Public Sub New(ByVal session As Session)
            MyBase.New(session)
        End Sub

        Private _customer As Customer
        <Association>
        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
End Namespace

Intermediate Class

This technique allows you to implement a many-to-many relationship in one assembly (ClassLibrary2) without changing classes from another assembly (ClassLibrary1). In this example, the CustomerToOrderLink class serves as a link between the Customer and Order classes. The Customer class uses a collection of CustomerToOrderLink objects to get related Order instances:

Assembly: ClassLibrary2.dll

csharp
using DevExpress.Xpo;

namespace ClassLibrary2 {
    public class Customer : XPObject {
        public Customer(Session session) : base(session) { }
        //...
        [Association, Aggregated]
        public XPCollection<CustomerToOrderLink> Orders {
            get { return GetCollection<CustomerToOrderLink>(nameof(Orders)); }
        }
    }
    public class CustomerToOrderLink : XPObject {
        public CustomerToOrderLink(Session session) : base(session) { }

        private Customer customer;
        [Association]
        public Customer Customer {
            get { return customer; }
            set { SetPropertyValue(nameof(Customer), ref customer, value); }
        }

        private ClassLibrary1.Order order;
        public ClassLibrary1.Order Order {
            get { return order; }
            set { SetPropertyValue(nameof(Order), ref order, value); }
        }
    }
}
vb
Imports DevExpress.Xpo

Namespace ClassLibrary2
    Public Class Customer
        Inherits XPObject

        Public Sub New(ByVal session As Session)
            MyBase.New(session)
        End Sub
        '...
        <Association, Aggregated>
        Public ReadOnly Property Orders() As XPCollection(Of CustomerToOrderLink)
            Get
                Return GetCollection(Of CustomerToOrderLink)(NameOf(Orders))
            End Get
        End Property
    End Class

    Public Class CustomerToOrderLink
        Inherits XPObject

        Public Sub New(ByVal session As Session)
            MyBase.New(session)
        End Sub

        Private _customer As Customer
        <Association>
        Public Property Customer() As Customer
            Get
                Return _customer
            End Get
            Set(ByVal value As Customer)
                SetPropertyValue(NameOf(Customer), _customer, value)
            End Set
        End Property

        Private _order As ClassLibrary1.Order
        Public Property Order() As ClassLibrary1.Order
            Get
                Return _order
            End Get
            Set(ByVal value As ClassLibrary1.Order)
                SetPropertyValue(NameOf(Order), _order, value)
            End Set
        End Property
    End Class
End Namespace

Dynamic Members

This technique allows you to implement one-to-many and many-to-many relationships between classes without changing their source code. It uses XPClassInfo to create members dynamically at runtime. Refer to the following topic for more information: XPClassInfo.CreateMember Method.

This example adds the Orders collection to the Customer class, and the Customer reference to the Order class. Call this code on an application startup before you initialize a data layer.

csharp
using DevExpress.Xpo;
using DevExpress.Xpo.DB;
using DevExpress.Xpo.Metadata;
using ClassLibrary1;
using ClassLibrary2;

ReflectionDictionary dictionary = new ReflectionDictionary();
dictionary.CollectClassInfos(typeof(Order), typeof(Customer));

XPClassInfo customerInfo = dictionary.QueryClassInfo(typeof(Customer));
XPClassInfo orderInfo = dictionary.QueryClassInfo(typeof(Order));
customerInfo.CreateMember("Orders", typeof(XPCollection<Order>), true, false, new AssociationAttribute("Customer-Orders"), new AggregatedAttribute());
orderInfo.CreateMember("Customer", customerInfo, new AssociationAttribute("Customer-Orders"));

XpoDefault.DataLayer = XpoDefault.GetDataLayer(connectionString, dictionary, AutoCreateOption.DatabaseAndSchema);
vb
Imports DevExpress.Xpo
Imports DevExpress.Xpo.DB
Imports DevExpress.Xpo.Metadata
Imports ClassLibrary1
Imports ClassLibrary2

Private dictionary As New ReflectionDictionary()
dictionary.CollectClassInfos(GetType(Order), GetType(Customer))

Dim customerInfo As XPClassInfo = dictionary.QueryClassInfo(GetType(Customer))
Dim orderInfo As XPClassInfo = dictionary.QueryClassInfo(GetType(Order))
customerInfo.CreateMember("Orders", GetType(XPCollection(Of Order)), True, False, New AssociationAttribute("Customer-Orders"), New AggregatedAttribute())
orderInfo.CreateMember("Customer", customerInfo, New AssociationAttribute("Customer-Orders"))

XpoDefault.DataLayer = XpoDefault.GetDataLayer(connectionString, dictionary, AutoCreateOption.DatabaseAndSchema)

These members are available in the UI of controls bound to XPO data sources, such as XPCollection and XPServerCollectionSource. They are not available in LINQ sources (XPQuery, LinqServerModeSource).

Use the XPClassInfo.FindMember method to access members in code and the XPMemberInfo.GetValue and XPMemberInfo.SetValue methods to get and change their values.