KB Article T639653
Visible to All Users

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

Symptoms

You may notice the following side-effects in a Web ListView (ASP.NET WebForms and ASP.NET Core Blazor) while it may work fine in WinForms:

  • A wrong DetailView may be selected when an unsaved record is clicked in ListView;
  • ListView may have no selection column;
  • View.SelectedObjects.Count is 0 in code even though records are selected in ListView;
  • All nested ListView records are selected at once when you selected only one record.
  • In inline edit or batch mode, all records may become selected or editable;
  • The EditAction of ListViewController can be disabled;
  • A Detail View is empty;
  • You get the "Requested object is not found and cannot be processed." error.
    These effects are especially frequent in a non-persistent class ListView or a nested ListView for an aggregated details collection with newly added or unsaved records.

Explanation

All new records added to the ListView and not yet saved to the database will be assigned with a temporary key value (e.g. -1 or an empty Guid/String value depending on your key type). In a Web application, ListView uses a business class key property to identify records, because there is no way to access real business objects from the web browser. Hence, there is a requirement that each business object must have a unique value assigned to the key property. ASPxGridView, DxDataGrid and other data-bound controls require this for the correct operation of such features like selection, deleting, filtering, sorting, grouping and the standard XAF functionality that depends on them (see also ASPxGridBase > KeyFieldName).
If a key property is missing in a business class completely or if a key property is not initialized with a unique value immediately after the record is created, these duplicate or invalid records may lead to a data-bound control malfunction as expected.

Solutions

1. BaseObject descendants for EF Core and XPO ORM Data Models

In XAF solutions created via the Solution Wizard, all classes inherited from BaseObject (EF Core) and BaseObject (XPO) already initialize its Oid key property with a unique System.Guid value right after an object is materialized. For XPO, additionally make sure that the OidInitializationMode option is still set to AfterConstruction.

2. XPObject descendants and custom base classes

2.1.  A general recommendation for XPObject and custom base persistent classes is to provide a unique key value in the overridden AfterConstruction method. Note that XPObject with its integer auto-generated Oid key property receives a unique value from the database server only after it is successfully saved to a data store. So, it is also related to the aforementioned side effects by default. It is fully up to you to decide which method you will use to guarantee uniqueness depending on planned use-case scenarios, concurrency and other project requirements. In the simplest case, you can get a total number of records +1 like in Q371449 , implement a more complex solution from E4904 or even use direct SQL. Refer to the An overview of approaches to implementing a user-friendly sequential number for use with an XPO business class article for more details.
2.2.  When new records are being created in a nested ListView, you can commit a master object immediately after adding a child object. Such UI-level solutions are less recommended (e.g., when it is not possible to immediately save a master object due to validation errors), but still may be suitable in certain scenarios. Refer to the Controller in T541706 and the example with the overridden XafApplication > GetObjectSpaceToShowDetailViewFrom method in T167796 for more information.
2.3. Very often, switching to BaseObject (or another class with the System.Guid key property) may be the simplest solution with comparable trade offs.

3. Non-persistent classes

3.1. Inherit the NonPersistentBaseObject class (v20.1.6+) that has a System.Guid key property (Oid) initialized with unique values.
3.2. Use the DevExpress.ExpressApp.Data.Key attribute to mark an object property as a key and manually generate unique values when materializing an object. For simplicity, you can use the System.Guid key and the System.Guid.NewGuid method.

How to choose a base persistent class or key property type

In XAF apps, we prefer BaseObject and NonPersistentBaseObject with a Guid key. It helps us and XAF users avoid this and many other issues while keeping things as simple as possible. Note that the use of Guid vs Int32 PK is rather a religious or highly debated in the community question. Both options can be very good and are widely used in production. Note that in certain scenarios with large tables having GUID as a primary key, performance of INSERT SQL statements can be degraded due to fragmentation. From our experience, this can be solved by XpoDefault.GuidGenerationMode (or using other means for generating sequential values like in T569076) or by establishing proper database maintenance.

See Also

Web - ASPxGridListEditor loads the entire data set in Server Mode when ShowSelectionColumn is set to True (the "Select All" checkbox is missing)

Search keywords

Web, unsaved, uncommitted, newly created, new, Oid, XPObject, selection column, selected, edit, editing, nested collection, selection column, aggregated, missing column, cannot open

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.