Description:
Can I override properties of my XPO business objects?
Answer:
NO. Overridden properties are unsupported in both XAF & XPO. In the past, we described workarounds with some limitations in this article, but over the years it created more problems than value. We don't recommend this approach (use it at your own risk).
We agree that overriding regular class properties is often handy. This concept, unfortunately, does not play well with database table structures (one physical column in the database) and consequently ORM objects.
If properties should have different attributes and logic in descendants, consider the following options:
- Do not declare such properties in the base class. Instead, declare different properties with required logic in descendants and show/hide them in required Views. Note that you can clone Views to have different settings for the base class and descendants.
- Apply customizations to corresponding View members in the Application Model (for instance, create View items with the same PropertyName, but different Id and Caption).
- Introduce virtual methods in the base class and call them from the base class properties. Override these virtual methods in descendants. This will work when DataAccessMode = Client.
- Use the IIF and IsExactType/IsInstanceOfType criteria functions in the base class to provide logic depending on a descendant type (for instance, for PersistentAliasAttribute). If DataAccessMode = Server, DataView or InstantFeedback, use the XPO Upcasting feature when you refer to descendant class properties in criteria for base classes. Consider the following example with the PersistentAlias attribute within the base class:
C#[PersistentAlias("iif(IsExactType(This,'YourSolutionName.Module.EmployeeBase'), Name, " +
"IsExactType(This,'YourSolutionName.Module.LocalEmployee'), <LocalEmployee>InsurancePolicyNumber, " +
"IsExactType(This,'YourSolutionName.Module.ForeignEmployee'), <ForeignEmployee>VisaExpirationDate, 'N/A')")]
public string DisplayNameBasedOnDescendantType {
get { return Convert.ToString(EvaluateAlias(nameof(DisplayNameBasedOnDescendantType))); }
}
================================
OLD:
There is no unambiguous answer to this question because everything depends on how you would override persistent properties. Let's split all the possible situations into two categories in which we are mostly interested when developing applications using XAF and XPO:
- You override a property and mark it with an attribute from the DevExpress.Xpo namespace;
- You override a property and mark it with any other attribute or add some code to change the default behavior of the property.
Since v2009 vol2 version it is not possible to work in the first scenario.
This is because during the internal initialization of the XPO's ReflectionClassInfo class, the following exception will be thrown:
"Member 'MemberName' and its attribute 'AttributeName' are ignored. The member with the same name is already declared in the base class 'ClassName'. To suppress this exception, set DevExpress.Xpo.Metadata.ReflectionClassInfo.SuppressSuspiciousMemberInheritanceCheck to True.".
This exception occurs when an overridden property has attributes from the DevExpress.Xpo namespace applied. The exception is thrown because overridden properties are not supported by XPO. When you override a property of the base class, it can cause a mismatch between the database and business classes. A column is already created in the database table for the virtual property. Overridden properties use the same column and cannot modify their parameters. So, there is no point in applying attributes from the DevExpress.Xpo namespace to overridden properties.
The static DevExpress.Xpo.Metadata.ReflectionClassInfo.SuppressSuspiciousMemberInheritanceCheck property allows you to temporarily suppress exceptions caused by applying attributes to overridden properties. If the SuppressSuspiciousMemberInheritanceCheck property is set to true, the attributes from the DevExpress.Xpo namespace, applied to overridden properties, are still ignored, but exceptions aren't thrown. Because of this, the SuppressSuspiciousMemberInheritanceCheck property shouldn't be used. If your application uses overridden properties, make sure that they don't have attributes from the DevExpress.Xpo namespace applied. If there are such attributes, remove them. Setting the SuppressSuspiciousMemberInheritanceCheck property to true may hide a potential design problem, but cannot address it.
However, it is possible to partially work in the second scenario.
Mostly, XAF copies the XPO's model of work with overridden properties, but there are some exceptions which you can use in your application (see also the IMPORTANT NOTES section below).
Please check the example attached to this KB Article for more details. Look at the DocumentBase class and its overridden Author property (this property is defined in the base Note class). Several attributes are applied to this property to hide the property in views:
C#public abstract class DocumentBase : Note {
[VisibleInDetailView(false)]
[VisibleInListView(false)]
[VisibleInLookupListView(false)]
public new string Author {
get { return base.Author; }
set { base.Author = value; }
}
If you open any View of DocumentType1 class (a descendant of the DocumentBase) you will see that there is no Author property there, by default:
So, these XAF attributes work fine. Even if you look at the DocumentType2 class (one more descendant of the DocumentBase class) in which the Author property is again overridden:
C#public class DocumentType2 : DocumentBase {
[RuleRequiredField(null, DefaultContexts.Save)]
[VisibleInDetailView(true)]
[VisibleInListView(true)]
[VisibleInLookupListView(true)]
public new string Author {
get { return base.Author; }
set { base.Author = value; }
}
and open any View of this class you will notice that attributes added to the overridden property work fine as well:
One more example - on overriding properties is possible and useful when you want to change the caption of your property in the UI. Please look at the Name property in the descendants of the DocumentBase class:
C#[System.ComponentModel.DisplayName("Document Of Type 1 Name")]
public new string Name {
get { return base.Name; }
set { base.Name = value; }
}
You may ask yourself - why and how does it work? The answer is quite simple. In the examples shown above we overrode the properties with the help of the new keyword. Using it means creating a new non-persistent property with the same name as the base property. So, this new property has no relation to the base property, and it works like a new regular non-persistent property. If you look at the descendant class with such an overridden property you will find that a new member is created under the class node, when by default, members of the base classes are shown only under the base class:
However, not all attributes can be applied and can work in this manner for overridden properties. For instance, when one validation attribute is applied to a base property and another validation attribute is applied to an overridden property. In this case the latter won't work (in our situation this will happen if we mark the overridden Name property with one more validation attribute). This behavior is by design.
IMPORTANT NOTES
- It is only possible to hide the property in the base class by using the new keyword if you want to provide custom logic or attributes for it. Take special note that this new property will be treated as non-persistent and will not be usable in server-side data processing (e.g., DataAccessMode = Server, DataView or InstantFeedback, criteria, validation, etc.).
Overriding virtual properties in the derived class using the override keyword is not possible and will never work either in XPO or XAF. For more details, please refer to the beginning of this article. See also the Versioning with the Override and New Keywords help topic for more details. - The scenarios above are quite simple and are more exceptions that work fine than built-in features of XAF. Some attributes that do not affect the representation of a property in UI may not work - these are attributes that are related to binding a property to data, for instance validation attributes.
- In general, there are few scenarios where overriding properties of your business objects will be really useful. In most cases, it is possible to avoid overriding by changing the design of the business model, or by using controllers.
guys, this stuff with new keywork would be great that there is not one small problem with Column Chooser. After several "new" steps in every class I have property Status that behaves as expected but when you have to add some new field from Column Chooser there you find columns with same name. Users are little bit confused. How to remove this extra properties?
Hello Goran,
To process your post more efficiently, I created a separate ticket on your behalf: T281643: How to remove base class properties from the Column Chooser when overriding them in descendants. This ticket is currently in our processing queue. Our team will address it as soon as we have any updates.
Hello,
I have 2 questions:
>>When you override a property of the base class, it can cause a mismatch between the database and business classes. A column is already created in the database table for the virtual property. Overridden properties use the same column and cannot modify their parameters. So, there is no point in applying attributes from the DevExpress.Xpo namespace to overridden properties.
What if the base class is nonpersistent or abstract? Since it involve nothing to the database,could it probably be excepted in the future?
If overriding is not recommended, What is the recommended way to centralize common logic from several classes?
Thank you
Hello Paul,
I've created a separate ticket on your behalf (T416738: Override properties of business objects). It has been placed in our processing queue and our team will address it as soon as we have any updates.
While defining Member Permissions in the the Security System on an descendant class with a property overridden using the approach above, a duplicate key exception is thrown when clicking the drop down to show the properties to assign permission. when I removed the overridden properties, the editor works as expected.
Hello Scott ,
I've created a separate ticket on your behalf (T548158: Defining Member Permissions on an descendant class with a property overridden using K18270 approach, a duplicate key exception is thrown). It has been placed in our processing queue and will be answered shortly.