Skip to main content
.NET 6.0+

Use XPO Upcasting in XAF

  • 4 minutes to read

In this topic, you will learn how to use the Upcasting feature of XPO in XAF. It is useful when you need to combine base and derived classes in a single query.

The following business model will be implemented to demonstrate the UpCasting.

UpCasing1

The code below describes the persistent class hierarchy:

[DefaultClassOptions]
[System.ComponentModel.DefaultProperty(nameof(Title))]
   public class Department : BaseObject {
   private string title;
   private string office;
   public Department(Session session) : base(session) {}
   public string Title {
      get {return title;}
      set {
         SetPropertyValue(nameof(Title), ref title, value);
      }
   }
   public string Office {
      get {return office;}
      set {
         SetPropertyValue(nameof(Office), ref office, value);
      }
   }
   [Association("Department-Employees")]
   public XPCollection<EmployeeBase> Employees {
      get {return GetCollection<EmployeeBase>(nameof(Employees));}
   }
}

public class EmployeeBase : BaseObject {
   public EmployeeBase(Session session) : base(session) {}
   private string name;
   private string email;
   public string Name {
      get {return name;}
      set {
         SetPropertyValue(nameof(Name), ref name, value);
      }
   }
   public string Email {
      get {return email;}
      set {
         SetPropertyValue(nameof(Email), ref email, value);
      }
   }
   private Department department;
   [Association("Department-Employees")]
   public Department Department {
      get {return department;}
      set {
         SetPropertyValue(nameof(Department), ref department, value);
      }
   }
}

[DefaultClassOptions]
public class LocalEmployee : EmployeeBase {
   public LocalEmployee(Session session): base(session) {}
   private string insurancePolicyNumber;
   public string InsurancePolicyNumber {
      get {return insurancePolicyNumber;}
      set {
         SetPropertyValue(nameof(InsurancePolicyNumber), ref insurancePolicyNumber, value);
      }
   }
}

[DefaultClassOptions]
public class ForeignEmployee : EmployeeBase {
   public ForeignEmployee(Session session): base(session) {}    
   private DateTime visaExpirationDate;
   public DateTime VisaExpirationDate {
      get {return visaExpirationDate;}
      set {
         SetPropertyValue(nameof(VisaExpirationDate), ref visaExpirationDate, value);
      }
   }
}

In the code above, the Department, LocalEmployee and ForeignEmployee classes use the DefaultClassOptions attribute. To learn more, refer to the Data Annotations in Data Model topic.

Now, run the Windows Forms, ASP.NET Web, or ASP.NET Core Blazor application. Invoke a Department Detail View:

UpCasting3

The nested Employees List View displays the properties of the EmployeeBase class only. This behavior is by design. However, it is better to display Employee class descendant specific properties in the Employees List View. With the UpCasting feature, this is accomplished with ease.

To add required columns to the List View that represents the Department.Employees collection, invoke the Model Editor. Locate the Views | Department_Employees_ListView | Columns node. Add two additional child nodes via the context menu. Specify their PropertyName property by the following values:

  • <LocalEmployee>InsurancePolicyNumber
  • <ForeignEmployee>VisaExpirationDate

These values will be recognized by XPO, and the LocalEmployee.InsurancePolicyNumber and ForeignEmployee.VisaExpirationDate properties will be displayed for objects retrieved from the database to the Department.Employees collection.

In addition, set the “Insurance Policy Number” and “Visa Expiration Date” values to the Caption property of the newly added columns.

Run the application and invoke the Department Detail View once again:

UpCasting2

You can see that the properties of the EmployeeBase class descendants are displayed together with the EmployeeBase class properties.