Example E3473
Visible to All Users

How to dynamically create a read-only calculated (persistent alias) property

Files to look at:

When building and extending persistent classes at runtime, it is often desirable to create a non-persistent calculated property. Currently available XPClassInfo.CreateMember method overrides are only capable of creating writable XPCustomMemberInfo instances and the XPCustomMemberInfo.ReadOnly property cannot be changed.

This example demonstrates how to create a custom XPAliasedMemberInfo class inherited directly from XPMemberInfo. In this class constructor, we add PersistentAliasAttribute with a specified expression, and override the GetValue method to evaluate the alias expression in the same manner as it is done in the XPBaseObject class. The read-only behavior is achieved by passing an argument to the base class constructor.

Also, an extender is implemented to provide additional methods for XPClassInfo class.

Does this example address your development requirements/objectives?

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

Example Code

ConsoleApplication17/Program.cs
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using DevExpress.Xpo; using DevExpress.Xpo.Metadata; using DevExpress.Data.Filtering; namespace ConsoleApplication17 { class Program { static void Main(string[] args) { XpoDefault.DataLayer = new SimpleDataLayer(new DevExpress.Xpo.DB.InMemoryDataStore()); XpoDefault.Session = null; using (UnitOfWork uow = new UnitOfWork()) { uow.ClearDatabase(); TestClass c1 = new TestClass(uow); c1.Name = "aaa"; c1.Email = "e@mail.com"; TestClass c2 = new TestClass(uow); c2.Name = "bbb"; c2.Email = "nobody@w3.com"; c2.Master = c1; uow.CommitChanges(); } XPClassInfo ci = XpoDefault.DataLayer.Dictionary.GetClassInfo(typeof(TestClass)); ci.CreateAliasedMember("DisplayName", typeof(string), "concat([Name],' (',[Email],')',iif([Master] is null,'',Concat(' managed by ',[Master].Name)))"); using (UnitOfWork uow = new UnitOfWork()) { XPCollection<TestClass> xpc = new XPCollection<TestClass>(uow, CriteriaOperator.Parse("Contains([DisplayName],'w3')")); System.Diagnostics.Debug.Assert(xpc.Count == 1); System.Diagnostics.Debug.Assert(xpc[0].Name == "bbb"); XPMemberInfo mi = xpc[0].ClassInfo.FindMember("DisplayName"); System.Diagnostics.Debug.Assert(mi!= null && mi.IsReadOnly && mi.IsAliased); System.Diagnostics.Debug.Assert(object.Equals(mi.GetValue(xpc[0]), "bbb (nobody@w3.com) managed by aaa")); } } } public class TestClass : XPObject { public TestClass(Session s) : base(s) { } public string Name { get { return GetPropertyValue<string>("Name"); } set { SetPropertyValue<string>("Name", value); } } public string Email { get { return GetPropertyValue<string>("Email"); } set { SetPropertyValue<string>("Email", value); } } public TestClass Master { get { return GetPropertyValue<TestClass>("Master"); } set { SetPropertyValue<TestClass>("Master", value); } } } }
ConsoleApplication17/XPAliasedMemberInfo.cs
C#
using System; using DevExpress.Data.Filtering; using DevExpress.Data.Filtering.Helpers; namespace DevExpress.Xpo.Metadata { public class XPAliasedMemberInfo : XPMemberInfo { readonly string propertyName; readonly Type propertyType; public XPAliasedMemberInfo(XPClassInfo owner, string propertyName, Type propertyType, string expression) : base(owner, true) { if (propertyName == null) throw new ArgumentNullException("propertyName"); this.propertyName = propertyName; this.propertyType = propertyType; Owner.AddMember(this); this.AddAttribute(new PersistentAliasAttribute(expression)); } public override string Name { get { return propertyName; } } public override bool IsPublic { get { return true; } } public override Type MemberType { get { return propertyType; } } protected override bool CanPersist { get { return false; } } public override object GetValue(object theObject) { bool caseSensitive = XpoDefault.DefaultCaseSensitive; if (theObject is DevExpress.Xpo.Helpers.ISessionProvider) { caseSensitive = ((DevExpress.Xpo.Helpers.ISessionProvider)theObject).Session.CaseSensitive; } PersistentAliasAttribute persistentAliasAttribute = (PersistentAliasAttribute)this.GetAttributeInfo(typeof(PersistentAliasAttribute)); return new ExpressionEvaluator(Owner.GetEvaluatorContextDescriptor(), CriteriaOperator.Parse(persistentAliasAttribute.AliasExpression, new object[0]), caseSensitive, Owner.Dictionary.CustomFunctionOperators).Evaluate(theObject); } public override void SetValue(object theObject, object theValue) { } public override bool GetModified(object theObject) { return false; } public override object GetOldValue(object theObject) { return GetValue(theObject); } public override void ResetModified(object theObject) { } public override void SetModified(object theObject, object oldValue) { } } #region .NET Framework 3+ Extender public static class XPAliasedMemberInfoExtender { public static XPAliasedMemberInfo CreateAliasedMember(this XPClassInfo self, string name, Type type, string expression) { return XPAliasedMemberInfoExtender.CreateAliasedMember(self, name, type, expression, null); } public static XPAliasedMemberInfo CreateAliasedMember(this XPClassInfo self, string name, Type type, string expression, Attribute[] attrs) { XPAliasedMemberInfo result = new XPAliasedMemberInfo(self, name, type, expression); if (attrs != null) { foreach (Attribute a in attrs) { result.AddAttribute(a); } } return result; } } #endregion }

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.