Add the DBColumn.IsCalculated property and extend built-in database providers to fill it. This feature is necessary to prevent the ORM Data Model wizard from generating persistent properties for such columns.
We have closed this ticket because another page addresses its subject:
How to map a property to a read-only database columnRecognize calculated columns when retrieving database schema
Answers approved by DevExpress Support
We have added support for read-only database columns in XPO. If you would like to test this feature prior to the official 18.2 release, get the preview build in the How to map a property to a read-only database column ticket. Your feedback is welcome.
Yes, this is a much needed feature. Often there are calculated fields that are very slow to execute using the PersistentAlias expressions. These same calculated fields execute much faster from the server. As it is now, XPO loads a table with these columns fine, but will error when attempting to update the data due to the calculated field.
Is there a way to override the save behavior to exclude the calculated field?
A great feature would be able to decorate an XPO field with something like [Persistent("CalcColumn", ExcludeFromUpdate := true)
Thanks,
-Chad
Hello Chad,
We appreciate your feedback. You can find a solution for this in the Support read-only persistent properties ticket. Thanks.
Thanks Dennis. I was able to implement what I needed using the reference you provided.
For Example:
/// <summary>
/// A custom object space provider to create a custom unit of work to perform special handling such as
/// allowing for XPO fields to be specified as "ReadOnly" preventing them from being included in the
/// update statements to the database. For example, when using a computed column on a database table.
/// </summary>
/// <remarks>
/// To activate this object space provider, you must override the CreateDefaultObjectSpaceProvider in WinApplication
/// </remarks>
public class XPObjectSpaceProviderEx : XPObjectSpaceProvider
{
public XPObjectSpaceProviderEx(string connectionString, IDbConnection connection) : base(connectionString, connection) { }
protected override UnitOfWork CreateUnitOfWork(IDataLayer dataLayer)
{
return new UnitOfWorkEx(dataLayer);
}
}
public class UnitOfWorkEx : UnitOfWork
{
public UnitOfWorkEx() { }
public UnitOfWorkEx(XPDictionary dictionary) : base(dictionary) { }
public UnitOfWorkEx(IDataLayer layer, params IDisposable[] disposeOnDisconnect) : base(layer, disposeOnDisconnect) { }
public UnitOfWorkEx(IObjectLayer layer, params IDisposable[] disposeOnDisconnect) : base(layer, disposeOnDisconnect) { }
protected override MemberInfoCollection GetPropertiesListForUpdateInsert(object theObject, bool isUpdate, bool addDelayedReference)
{
MemberInfoCollection result = new MemberInfoCollection(this.GetClassInfo(theObject));
foreach (XPMemberInfo mi in base.GetPropertiesListForUpdateInsert(theObject, isUpdate, addDelayedReference))
{
// if (mi is ServiceField || mi.GetModified(theObject)) // Note requires XpoDefault.TrackPropertiesModifications = true; in Main()
if (mi is ServiceField
|| !mi.Attributes.Any(attr => (attr as CustomAttribute) != null
&& string.Equals((attr as CustomAttribute).Name, "readonly", StringComparison.OrdinalIgnoreCase)
&& !string.Equals((attr as CustomAttribute).Value, "false", StringComparison.OrdinalIgnoreCase)))
result.Add(mi);
}
return result;
}
}
Then I decorate my private variable like this:
[Persistent("TestComputedColumn"), Custom("ReadOnly", null)]
private string _testComputedColumn;
Thanks again,
-Chad