Ticket T150240
Visible to All Users
Duplicate

We have closed this ticket because another page addresses its subject:

How to customize the UnitOfWork behavior in XPO-based XAF applications

Security: Persist changed properties only when saving a changed business object record

created 10 years ago

Hello XAF Team,

If the complex security (member permissions) is used in an application, then saving a changed business object record will write all properties back to the database.

The above behavior exists in v12.2.x. Has this situation been improved since v12.2?

Expected result: Only changed properties will be updated in the database, such that member permissions can be used to include only a few updatable properties with Write permission.

Regards,
James Zhong

Answers approved by DevExpress Support

created 10 years ago (modified 6 years ago)

Hello James,

This behavior is standard for XPO and is not related to the Security System. When an object is saved, a query that includes all persistent properties is sent to a database.
If you are concerned about the security (e.g. that it is possible to modify a read-only property in code and write these changes to the database), use the Integrated or Middle-Tier security instead of the UI-Level security. These modes will not allow changing read-only properties in code. Refer to the New Security System topic for additional information.

In addition, XPO provides the following ways to exclude some properties from the INSERT and UPDATE queries:

  1. Use the FetchOnly attribute, as described in the following blog post: XPO - Easy Way to Map a Property to a Read-Only Database Column (v18.2).
  2. Make these properties delayed and pass True to the DelayedAttribute.UpdateModifiedOnly parameter.
  3. Create a Session's descendant and override its GetPropertiesListForUpdateInsert method. Here is an example of how to do this in an XAF application that uses the Integrated Security (SecuredObjectSpaceProvider):
C#
XpoDefault.TrackPropertiesModifications = true; winApplication.CreateCustomObjectSpaceProvider += (sender, e) => { e.ObjectSpaceProvider = new MySecuredObjectSpaceProvider((ISelectDataSecurityProvider)winApplication.Security, e.ConnectionString, e.Connection, false); }; ... public class MySecuredObjectSpaceProvider : SecuredObjectSpaceProvider { private ISelectDataSecurityProvider selectDataSecurityProvider; public MySecuredObjectSpaceProvider(ISelectDataSecurityProvider provider, string connectionString, IDbConnection connection, bool threadSafe) : base(provider, connectionString, connection, threadSafe) { selectDataSecurityProvider = provider; } protected override UnitOfWork CreateDirectUnitOfWork(IDataLayer dataLayer) { return new MyUnitOfWork(dataLayer); } //Prior to 17.2 //protected override UnitOfWork CreateUnitOfWork(IDataLayer dataLayer) { // UnitOfWork directBaseUow = new MyUnitOfWork(dataLayer); // SessionObjectLayer currentObjectLayer = new SecuredSessionObjectLayer(AllowICommandChannelDoWithSecurityContext, directBaseUow, true, null, new SecurityRuleProvider(XPDictionary, selectDataSecurityProvider.CreateSelectDataSecurity()), null); // return new MyUnitOfWork(currentObjectLayer, directBaseUow); //} } public class MyUnitOfWork : UnitOfWork { public MyUnitOfWork(IDataLayer dataLayer) : base(dataLayer) { } public MyUnitOfWork(IObjectLayer objectLayer, params IDisposable[] disposeOnDisconnect) : base(objectLayer, disposeOnDisconnect) { } protected override MemberInfoCollection GetPropertiesListForUpdateInsert(object theObject, bool isUpdate, bool addDelayedReference) { MemberInfoCollection defaultMembers = base.GetPropertiesListForUpdateInsert(theObject, isUpdate, addDelayedReference); if (TrackPropertiesModifications && isUpdate) { MemberInfoCollection members = new MemberInfoCollection(GetClassInfo(theObject)); foreach (XPMemberInfo member in defaultMembers) { if (member.GetModified(theObject)) { members.Add(member); } } return members; } else { return defaultMembers; } } }

Note that I have not tested this example in complex scenarios and do not guarantee that it works properly there.
See more examples in the How to customize the UnitOfWork behavior in XPO-based XAF applications article.

    Show previous comments (3)
    Anatol (DevExpress) 10 years ago

      Probably your Session's descendant is not used in the application. To use it instead of the default class (UnitOfWork), create a custom Object Space Provider and override its CreateUnitOfWork method. I have added an example to my initial answer.

        the OptimisticLockField seems to be updated many times even if no other properties on the table have changed.

        is there a way to change the behavior to only update that field if a property has changed?

        Anatol (DevExpress) 8 years ago

          Hello Scott,

          I've created a separate ticket on your behalf (T548971: How to update the OptimisticLockField only when persistent properties are changed). It has been placed in our processing queue and will be answered shortly.

          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.