Skip to main content
All docs
V24.2
.NET 8.0+

How to: Display a List View With Data From a Stored Procedure From the Navigation

  • 5 minutes to read

This example demonstrates how to show a List View with data fetched from a stored procedure from the Navigation. This example uses the Non-Persistent Objects to temporally store data from the stored procedure and the Northwind database. The stored procedure is defined as follows:

CREATE Procedure GetEmployees
AS
    SET NOCOUNT ON;
    SELECT * FROM Employees
GO

Create Non-Persistent Objects in the Platform-Agnostic Module

  1. In the platform-agnostic module (MySolution.Module), create the following non-persistent class:

    using DevExpress.ExpressApp.DC;
    using DevExpress.Persistent.Base;
    
    namespace YourSolutionName.Module.BusinessObjects {
        [DomainComponent, DefaultClassOptions]
        public class MyNonPersistentObject {
            [DevExpress.ExpressApp.Data.Key]
            public int EmployeeID { get; internal set; }
            public string FirstName { get; internal set; }
            public string LastName { get; internal set; }
            public string Title { get; internal set; }
        }
    }
    

    Note

    Internal/Friend setters are used in the non-persistent class to disable editing the properties because editing is not implemented in this example.

  2. Handle the OnObjectSpaceCreated event in the Application Builder code to subscribe to the NonPersistentObjectSpace events as described in the following help topic: How to: Display a Non-Persistent Object’s List View from the Navigation.

    File: MySolution.Blazor.Server/Startup.cs, MySolution.Win/Startup.cs, MySolution.WebApi/Startup.cs

    using DevExpress.ExpressApp;
    // ...
    builder.ObjectSpaceProviders.Events.OnObjectSpaceCreated = context => {
        NonPersistentObjectSpace npos = context.ObjectSpace as NonPersistentObjectSpace;
        if (npos != null) {
            // ...
        }
    };
    
  3. ORM-dependent code executes a stored procedure (the code uses Session in XPO and DbContext in EF Core). You can access the Session or DbContext through the corresponding persistent ObjectSpace. To allow the NonPersistentObjectSpace to access persistent ObjectSpaces, populate the CompositeObjectSpace.AdditionalObjectSpaces collection in the ObjectSpaceCreated event handler.

    File: MySolution.Blazor.Server/Startup.cs, MySolution.Win/Startup.cs, MySolution.WebApi/Startup.cs

    using DevExpress.ExpressApp;
    // ...
    builder.ObjectSpaceProviders.Events.OnObjectSpaceCreated = context => {
        CompositeObjectSpace os = e.ObjectSpace as CompositeObjectSpace;
        if (os != null && !(os.Owner is CompositeObjectSpace)) {
            var objectSpaceProviderService = context.ServiceProvider.GetRequiredService<IObjectSpaceProviderService>();
            var objectSpaceCustomizerService = context.ServiceProvider.GetRequiredService<IObjectSpaceCustomizerService>();
            os.PopulateAdditionalObjectSpaces(objectSpaceProviderService, objectSpaceCustomizerService);
        }
        NonPersistentObjectSpace npos = context.ObjectSpace as NonPersistentObjectSpace;
        if (npos != null) {
            // ...
        }
    };
    // ...
    
  4. To be able to filter and sort a List View, use the DynamicCollection class in the ObjectsGetting event handler to populate the e.Objects collection. To separate the Module code from business logic to fetch data, create an adapter class to handle the NonPersistentObjectSpace events. The following example demonstrates how to implement this: How to filter and sort Non-Persistent Objects.

    Note

    The capability to filter and sort non-persistent objects is supported only in Client data access mode. In XAF Blazor, the default data access mode for List Views is Queryable. Change the non-persistent List View’s data access mode to Client in XAF Blazor applications as described in the following topic: List View Data Access Modes.

    using DevExpress.ExpressApp;
    using System.Collections.Generic;
    
    namespace YourSolutionName.Module.BusinessObjects {
        class MyNonPersistentObjectAdapter {
            NonPersistentObjectSpace objectSpace;
            public MyNonPersistentObjectAdapter(NonPersistentObjectSpace npos) {
                objectSpace = npos;
                objectSpace.ObjectsGetting += Npos_ObjectsGetting;
            }
            private void Npos_ObjectsGetting(object sender, ObjectsGettingEventArgs e) {
                if (e.ObjectType != typeof(MyNonPersistentObject)) {
                    return;
                }
                var collection = new DynamicCollection(objectSpace, e.ObjectType, e.Criteria, e.Sorting, e.InTransaction);
                collection.FetchObjects += DynamicCollection_FetchObjects;
                e.Objects = collection;
            }
            private void DynamicCollection_FetchObjects(object sender, FetchObjectsEventArgs e) {
                if (e.ObjectType == typeof(MyNonPersistentObject)) {
                    e.Objects = GetDataFromSproc();
                    e.ShapeData = true;
                }
            }
            List<MyNonPersistentObject> GetDataFromSproc() {
                // ...
            }
        }
    }
    

    File: MySolution.Blazor.Server/Startup.cs, MySolution.Win/Startup.cs, MySolution.WebApi/Startup.cs

    using DevExpress.ExpressApp;
    // ...
    builder.ObjectSpaceProviders.Events.OnObjectSpaceCreated = context => {
        CompositeObjectSpace os = e.ObjectSpace as CompositeObjectSpace;
        if (os != null && !(os.Owner is CompositeObjectSpace)) {
            var objectSpaceProviderService = context.ServiceProvider.GetRequiredService<IObjectSpaceProviderService>();
            var objectSpaceCustomizerService = context.ServiceProvider.GetRequiredService<IObjectSpaceCustomizerService>();
            os.PopulateAdditionalObjectSpaces(objectSpaceProviderService, objectSpaceCustomizerService);
        }
        NonPersistentObjectSpace npos = context.ObjectSpace as NonPersistentObjectSpace;
        if (npos != null) {
            new MyNonPersistentObjectAdapter(npos);
        }
    };
    // ...
    

    The GetDataFromSproc method should contain ORM-dependent code to get data from a stored procedure.

Create XPO-Dependent Code to Get Data from a Stored Procedure

In XPO, use the Session.ExecuteQueryWithMetadata method to get data from a stored procedure. This method returns column names along with data. Refer to the following help topic for information on how to access data returned by the ExecuteQueryWithMetadata method: How to: Access Data in SQL Query Results.

Use the XPObjectSpace.Session property to access a Session instance. You can access an XPObjectSpace instance from the CompositeObjectSpace.AdditionalObjectSpaces collection.

using DevExpress.ExpressApp.Xpo;
using DevExpress.Xpo;
using DevExpress.Xpo.DB;
using System.Linq;

class MyNonPersistentObjectAdapter {
    // ...
    List<MyNonPersistentObject> GetDataFromSproc() {
        XPObjectSpace persistentObjectSpace = objectSpace.AdditionalObjectSpaces.OfType<XPObjectSpace>().First();
        Session session = persistentObjectSpace.Session;
        SelectedData results = session.ExecuteQueryWithMetadata("GetEmployees");
        Dictionary<string, int> columnNames = new Dictionary<string, int>();
        for (int columnIndex = 0; columnIndex < results.ResultSet[0].Rows.Length; columnIndex++) {
            string columnName = results.ResultSet[0].Rows[columnIndex].Values[0] as string;
            columnNames.Add(columnName, columnIndex);
        }
        List<MyNonPersistentObject> objects = new List<MyNonPersistentObject>();
        foreach (SelectStatementResultRow row in results.ResultSet[1].Rows) {
            MyNonPersistentObject obj = new MyNonPersistentObject();
            obj.EmployeeID = (int)row.Values[columnNames["EmployeeID"]];
            obj.FirstName = row.Values[columnNames["FirstName"]] as string;
            obj.LastName = row.Values[columnNames["LastName"]] as string;
            obj.Title = row.Values[columnNames["Title"]] as string;
            objects.Add(obj);
        }
        return objects;
    }
}

Create EF Core-Dependent Code to Get Data from a Stored Procedure

In EF Core, use the DbSet object’s RelationalQueryableExtensions.FromSqlRaw extension method to get data from a stored procedure. Create an entity class that should store data fetched from a stored procedure.

namespace YourSolutionName.Module.BusinessObjects {
    public class Employees {
        [System.ComponentModel.DataAnnotations.Key]
        public virtual int EmployeeID { get; set; }
        public virtual string FirstName { get; set; }
        public virtual string LastName { get; set; }
        public virtual string Title { get; set; }
    }
}

// Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.

Add the new entity class to the solution’s DbContext in the YourSolutionName.Module\BusinessObjects\YourSolutionNameDbContext.cs(vb) file.

using Microsoft.EntityFrameworkCore;

public class YourSolutionNameEFCoreDbContext : DbContext {
    // ...
    public DbSet<Employees> Employees { get; set; }
}

Get an EFCoreObjectSpace instance from the CompositeObjectSpace.AdditionalObjectSpaces collection in the GetDataFromSproc method.

Access the YourSolutionNameEFCoreDbContext instance from the EFCoreObjectSpace.DbContext property.

Call the YourSolutionNameEFCoreDbContext.Employees.FromSqlRaw method to get data from a stored procedure.

using DevExpress.ExpressApp.EFCore;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;

class MyNonPersistentObjectAdapter {
    // ...
    List<MyNonPersistentObject> GetDataFromSproc() {
        EFCoreObjectSpace persistentObjectSpace = objectSpace.AdditionalObjectSpaces.OfType<EFCoreObjectSpace>().First();
        YourSolutionNameEFCoreDbContext dbContext = (YourSolutionNameEFCoreDbContext)persistentObjectSpace.DbContext;
        IQueryable<Employees> results = dbContext.Employees.FromSqlRaw("GetEmployees");
        List<MyNonPersistentObject> objects = new List<MyNonPersistentObject>();
        foreach (Employees employees in results) {
            MyNonPersistentObject obj = new MyNonPersistentObject();
            obj.EmployeeID = employees.EmployeeID;
            obj.FirstName = employees.FirstName;
            obj.LastName = employees.LastName;
            obj.Title = employees.Title;
            objects.Add(obj);
        }
        return objects;
    }
}
See Also