How to: Link Classes Located in Different Assemblies
- 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
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); }
}
}
}
Assembly: ClassLibrary2.dll
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); }
}
}
}
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
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); }
}
}
}
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
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); }
}
}
}
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.
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);
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.