Example E250
Visible to All Users

XAF - Customize an XPO Business Model at Runtime

You can extend existing business classes without modifying their source code. For instance, when you work with an assembly that contains persistent classes.

This example modifies business classes declared in a separate project as follows:

  • Adds an attribute (DefaultClassOptionsAttribute)
  • Creates a simple persistent property (NewIntField)
  • Creates reference and collection properties linked by an association (one-to-many relationship between PersistentObject1 and PersistentObject2 classes)

Run application

Implementation Details

  1. Populate the AdditionalExportedTypes property with types from external storage to add them to the application.
    C#
    this.AdditionalExportedTypes.Add(typeof(MyXPOClassLibrary.PersistentObject1)); this.AdditionalExportedTypes.Add(typeof(MyXPOClassLibrary.PersistentObject2));
  2. Modify the added types as follows:
    • Call the AddAttribute method to add an attribute to an existing class.
      Note that by design you cannot dynamically add or remove the OptimisticLocking or DeferredDeletion attribute.
      C#
      ITypeInfo typeInfo1 = typesInfo.FindTypeInfo(typeof(PersistentObject1)); typeInfo1.AddAttribute(new DevExpress.Persistent.Base.DefaultClassOptionsAttribute());
    • Call the CreateMember method to create a new simple persistent property.
      C#
      IMemberInfo memberInfo0 = typeInfo1.FindMember("NewIntField"); if (memberInfo0 == null) { typeInfo1.CreateMember("NewIntField", typeof(int)); }
    • Use both AddAttribute and CreateMember methods to create new reference and collection properties linked by an association.
      C#
      ITypeInfo typeInfo2 = typesInfo.FindTypeInfo(typeof(PersistentObject2)); IMemberInfo memberInfo1 = typeInfo1.FindMember("PersistentObject2s"); IMemberInfo memberInfo2 = typeInfo2.FindMember("PersistentObject1"); if (memberInfo1 == null) { memberInfo1 = typeInfo1.CreateMember("PersistentObject2s", typeof(DevExpress.Xpo.XPCollection<PersistentObject2>)); memberInfo1.AddAttribute(new DevExpress.Xpo.AssociationAttribute("PersistentObject1-PersistentObject2s", typeof(PersistentObject2)), true); memberInfo1.AddAttribute(new DevExpress.Xpo.AggregatedAttribute(), true); } if (memberInfo2 == null) { memberInfo2 = typeInfo2.CreateMember("PersistentObject1", typeof(PersistentObject1)); memberInfo2.AddAttribute(new DevExpress.Xpo.AssociationAttribute("PersistentObject1-PersistentObject2s", typeof(PersistentObject1)), true); }
  3. Call the RefreshInfo(Type) method to refresh metadata for the modified types.
    C#
    typesInfo.RefreshInfo(typeof(PersistentObject1)); typesInfo.RefreshInfo(typeof(PersistentObject2));

Files to Review

Documentation

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

CustomizeXPOModel/MyXPOClassLibrary/PersistentObject1.cs
C#
using System; using System.ComponentModel; using DevExpress.Xpo; namespace MyXPOClassLibrary { public class PersistentObject1 : XPObject { public PersistentObject1(Session session) : base(session) { // This constructor is used when an object is loaded from a persistent storage. // Do not place any code here. } public override void AfterConstruction() { base.AfterConstruction(); // Place here your initialization code. } private string _stringPropertyName; public string StringPropertyName { get { return _stringPropertyName; } set { SetPropertyValue(nameof(StringPropertyName), ref _stringPropertyName, value); } } private int _intPropertyName; public int IntPropertyName { get { return _intPropertyName; } set { SetPropertyValue(nameof(IntPropertyName), ref _intPropertyName, value); } } } }
CustomizeXPOModel/MyXPOClassLibrary/PersistentObject2.cs
C#
using System; using DevExpress.Xpo; namespace MyXPOClassLibrary { public class PersistentObject2 : XPObject { public PersistentObject2(Session session) : base(session) { // This constructor is used when an object is loaded from a persistent storage. // Do not place any code here. } public override void AfterConstruction() { base.AfterConstruction(); // Place here your initialization code. } private string _Name; public string Name { get { return _Name; } set { SetPropertyValue(nameof(Name), ref _Name, value); } } } }
CustomizeXPOModel/CustomizeXPOModel.Module/Module.cs
C#
using System.ComponentModel; using DevExpress.ExpressApp; using DevExpress.ExpressApp.DC; using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl; using DevExpress.ExpressApp.Model; using DevExpress.ExpressApp.Actions; using DevExpress.ExpressApp.Editors; using DevExpress.ExpressApp.Updating; using DevExpress.ExpressApp.Model.Core; using DevExpress.ExpressApp.Model.DomainLogics; using DevExpress.ExpressApp.Model.NodeGenerators; using DevExpress.Xpo; using DevExpress.ExpressApp.Xpo; using MyXPOClassLibrary; namespace CustomizeXPOModel.Module; // For more typical usage scenarios, be sure to check out https://docs.devexpress.com/eXpressAppFramework/DevExpress.ExpressApp.ModuleBase. public sealed class CustomizeXPOModelModule : ModuleBase { public CustomizeXPOModelModule() { // // CustomizeXPOModelModule // RequiredModuleTypes.Add(typeof(DevExpress.ExpressApp.SystemModule.SystemModule)); RequiredModuleTypes.Add(typeof(DevExpress.ExpressApp.Objects.BusinessClassLibraryCustomizationModule)); RequiredModuleTypes.Add(typeof(DevExpress.ExpressApp.ConditionalAppearance.ConditionalAppearanceModule)); RequiredModuleTypes.Add(typeof(DevExpress.ExpressApp.Validation.ValidationModule)); this.AdditionalExportedTypes.Add(typeof(MyXPOClassLibrary.PersistentObject1)); this.AdditionalExportedTypes.Add(typeof(MyXPOClassLibrary.PersistentObject2)); } public override IEnumerable<ModuleUpdater> GetModuleUpdaters(IObjectSpace objectSpace, Version versionFromDB) { ModuleUpdater updater = new DatabaseUpdate.Updater(objectSpace, versionFromDB); return new ModuleUpdater[] { updater }; } public override void Setup(XafApplication application) { base.Setup(application); // Manage various aspects of the application UI and behavior at the module level. } public override void CustomizeTypesInfo(DevExpress.ExpressApp.DC.ITypesInfo typesInfo) { base.CustomizeTypesInfo(typesInfo); CalculatedPersistentAliasHelper.CustomizeTypesInfo(typesInfo); ITypeInfo typeInfo1 = typesInfo.FindTypeInfo(typeof(PersistentObject1)); typeInfo1.AddAttribute(new DevExpress.Persistent.Base.DefaultClassOptionsAttribute()); IMemberInfo memberInfo0 = typeInfo1.FindMember("NewIntField"); if (memberInfo0 == null) { typeInfo1.CreateMember("NewIntField", typeof(int)); } ITypeInfo typeInfo2 = typesInfo.FindTypeInfo(typeof(PersistentObject2)); IMemberInfo memberInfo1 = typeInfo1.FindMember("PersistentObject2s"); IMemberInfo memberInfo2 = typeInfo2.FindMember("PersistentObject1"); if (memberInfo1 == null) { memberInfo1 = typeInfo1.CreateMember("PersistentObject2s", typeof(DevExpress.Xpo.XPCollection<PersistentObject2>)); memberInfo1.AddAttribute(new DevExpress.Xpo.AssociationAttribute("PersistentObject1-PersistentObject2s", typeof(PersistentObject2)), true); memberInfo1.AddAttribute(new DevExpress.Xpo.AggregatedAttribute(), true); } if (memberInfo2 == null) { memberInfo2 = typeInfo2.CreateMember("PersistentObject1", typeof(PersistentObject1)); memberInfo2.AddAttribute(new DevExpress.Xpo.AssociationAttribute("PersistentObject1-PersistentObject2s", typeof(PersistentObject1)), true); } typesInfo.RefreshInfo(typeof(PersistentObject1)); typesInfo.RefreshInfo(typeof(PersistentObject2)); } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.