Ticket T167796
Visible to All Users
Duplicate

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

Web - How to avoid issues with data-bound controls due to missing or non-unique key values

All objects are selected / edited in a nested ListView after creating several aggregated objects without saving the master object

created 10 years ago

Hi Team,

I would like to report an issue found on the ListView Controller - Delete & Edit Functions.
Our team has confirmed this issue also on XAF's Main Demo: Contact Module -> Phone Numbers tab.

  1. Delete Function
          - 2nd item in the list view is selected for deletion, but on click of delete button, the 1st item gets deleted instead.
  2. Edit Function
         - when clicking the Inline Edit button, all items in the listview gets selected.
         - when clicking the Inline Edit button of the 2nd item, the 1st item details is shown instead of the 2nd item's details.

For reference, please check: http://screencast-o-matic.com/watch/c26wXOelM5

Can you kindly confirm if this is a bug on XAF ListView and if there is a fix for this issue?

Thank you.

Answers approved by DevExpress Support

created 10 years ago (modified 8 years ago)

Hello Ristie,

This behavior occurs because the grid control identifies rows by their keys, and by default, an object is generated only when the object is saved. Since PhoneNumbers is an aggregated collection, changes made in it are saved only when the master object (Contact) is saved. That is why you are seeing this side effect. To resolve the issue, set the BaseObject.OidInitializationMode or PhoneNumber.OidInitializationMode property to AfterConstruction to generate a key immediately when a new object is created:

C#
public sealed partial class MainDemoModule : ModuleBase { public MainDemoModule() { PhoneNumber.OidInitializationMode = OidInitializationMode.AfterConstruction; InitializeComponent(); }

If the problematic class is not inherited from the BaseObject class, use one of the following solutions:

  1. Implement a Guid key in your class and generate its value in the AfterConstruction method, as shown below.
C#
public override void AfterConstruction() { base.AfterConstruction(); Oid = XpoDefault.NewGuid(); }
  1. If you cannot change the key type, generate a new key using a custom code value when the object is created (for example, see How to generate a sequential and user-friendly identifier field within a business class).

  2. Change the DetailView's CollectionsEditMode to View in the Model Editor.

  3. Commit changes to the database immediately after the child object is saved. The easiest way to do this is to override the GetObjectSpaceToShowDetailViewFrom method of the WebApplication descendant from the WebApplication.cs file as follows:

C#
public class MainDemoWebApplication : WebApplication { ... public override IObjectSpace GetObjectSpaceToShowDetailViewFrom(Frame sourceFrame, Type objectType) { if (objectType == typeof(PhoneNumber) && sourceFrame.View != null && sourceFrame.View.Id == "Party_PhoneNumbers_ListView") { return CreateObjectSpace(objectType); } return base.GetObjectSpaceToShowDetailViewFrom(sourceFrame, objectType); }

This code creates a root Object Space instead of a nested one. Changes saved in this Object Space will be written to the database immediately.

    Comments (3)

      Hi Anatol,
      I see that Phone Number in MainDemo is a BaseObject.
      But, in our application, we are using the XPBaseObject.
      And we are also encountering the same issues that I mentioned.
      For XPBaseObject, I think the OidInitializationMode is not applicable.
      Is there any other way to resolve this?
      Thanks.

      Anatol (DevExpress) 10 years ago

        In this case, use one of the following solutions.

        1. Implement a Guid key in your class and generate its value in the AfterConstruction method, as shown below.
        C#
        public override void AfterConstruction() { base.AfterConstruction(); Oid = XpoDefault.NewGuid(); }
        1. If you cannot change the key type, generate a new key using a custom code value when the object is created (for example, see How to generate a sequential and user-friendly identifier field within a business class).

        2. Change the DetailView's CollectionsEditMode to View in the Model Editor.

        3. Commit changes to the database immediately after the child object is saved. The easiest way to do this is to override the GetObjectSpaceToShowDetailViewFrom method of the WebApplication descendant from the WebApplication.cs file as follows:

        C#
        public class MainDemoWebApplication : WebApplication { ... public override IObjectSpace GetObjectSpaceToShowDetailViewFrom(Frame sourceFrame, Type objectType) { if (objectType == typeof(PhoneNumber) && sourceFrame.View != null && sourceFrame.View.Id == "Party_PhoneNumbers_ListView") { return CreateObjectSpace(objectType); } return base.GetObjectSpaceToShowDetailViewFrom(sourceFrame, objectType); }

        This code creates a root Object Space instead of a nested one. Changes saved in this Object Space will be written to the database immediately.

          Thanks Anatol.
          Will check on these items and update you.

          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.