|
| 1 | +<!-- default badges list --> |
| 2 | +<!-- default badges end --> |
| 3 | +# Blazor Grid - Bind to Data Using XPO |
| 4 | + |
| 5 | +This example uses **DevExpress eXpress Persistent Objects (XPO) ORM** to bind the Blazor **DxGrid** to data stored in a database: a Web API backend queries XPO persistent objects and exposes data to the Blazor application through a [GridDevExtremeDataSource\<T\>](https://docs.devexpress.com/Blazor/DevExpress.Blazor.GridDevExtremeDataSource-1). |
| 6 | + |
| 7 | +The example covers the following implementation steps: |
| 8 | +* Configure XPO. |
| 9 | +* Implement a Web API endpoint that supports server-side data operations (paging, sorting, and filtering). |
| 10 | +* Connect DxGrid to the endpoint. |
| 11 | + |
| 12 | +As a result, the grid performs data operations on demand and loads only the records required for display. This keeps the solution efficient for large datasets. |
| 13 | + |
| 14 | +## Implementation Details |
| 15 | + |
| 16 | +### Configure the Server to Access Data Using XPO |
| 17 | + |
| 18 | +Follow the steps below to configure [XPO](https://docs.devexpress.com/XPO/2004/express-persistent-objects) in the [WebAPI](.\CS\DxGrid.BindToDataUsingXPO.WebAPI\DxGrid.BindToDataUsingXPO.WebAPI.csproj) project: |
| 19 | + |
| 20 | +1. In the [Program.cs](.\CS\DxGrid.BindToDataUsingXPO.WebAPI\Program.cs) file, register the XPO data layer and unit of work. |
| 21 | +1. Define persistent object types used in the app and a connection string: |
| 22 | + |
| 23 | + ```cs |
| 24 | + builder.Services.AddXpoDefaultDataLayer(ServiceLifetime.Singleton, dl => dl |
| 25 | + .UseConnectionString(builder.Configuration.GetConnectionString("WideWorldImportersExample")) |
| 26 | + .UseThreadSafeDataLayer(true) |
| 27 | + .UseConnectionPool(false) |
| 28 | + .UseAutoCreationOption(DevExpress.Xpo.DB.AutoCreateOption.DatabaseAndSchema) |
| 29 | + .UseEntityTypes(typeof(People), typeof(Orders), typeof(Customers)) |
| 30 | + ); |
| 31 | + builder.Services.AddXpoDefaultUnitOfWork(); |
| 32 | + ``` |
| 33 | + |
| 34 | +1. In the [BindToDataUsingXPO.WebAPI\Data\Orders.cs](.\CS\DxGrid.BindToDataUsingXPO.WebAPI\Data\Orders.cs), inherit persistent objects (such as `Orders`) from the `XPBaseObject` to expose properties that you want to map to database columns. |
| 35 | + |
| 36 | + ```cs |
| 37 | + public class Orders(Session session) : XPBaseObject(session) { |
| 38 | + [Key, Persistent("OrderID")] |
| 39 | + public int ID; |
| 40 | + |
| 41 | + private DateTime orderDate; |
| 42 | + public DateTime OrderDate { |
| 43 | + get => orderDate; |
| 44 | + set => SetPropertyValue(nameof(OrderDate), ref orderDate, value); |
| 45 | + } |
| 46 | + |
| 47 | + // ... |
| 48 | + } |
| 49 | + ``` |
| 50 | + |
| 51 | +### Expose Data Through a Web API Controller |
| 52 | + |
| 53 | +Create an API controller that queries the XPO `UnitOfWork`, shapes the result, and uses the `DevExtreme.AspNet.Data` library's [DataSourceLoader](https://devexpress.github.io/DevExtreme.AspNet.Data/net/api/DevExtreme.AspNet.Data.DataSourceLoader.html) to apply paging, sorting, and filtering based on the grid's load options: |
| 54 | + |
| 55 | +```cs |
| 56 | +[HttpGet] |
| 57 | +public ActionResult Get(DataSourceLoadOptions loadOptions) { |
| 58 | + try { |
| 59 | + var query = uow.Query<Orders>(); |
| 60 | + var projection = query.Select(p => new { |
| 61 | + Id = p.ID, |
| 62 | + p.OrderDate, |
| 63 | + p.ExpectedDeliveryDate, |
| 64 | + // ... |
| 65 | + }); |
| 66 | + |
| 67 | + loadOptions = loadOptions ?? new DataSourceLoadOptions(); |
| 68 | + loadOptions.PrimaryKey = new[] { "Id" }; |
| 69 | + loadOptions.PaginateViaPrimaryKey = true; |
| 70 | + var loadResult = DataSourceLoader.Load(projection, loadOptions); |
| 71 | + |
| 72 | + return Ok(loadResult); |
| 73 | + } |
| 74 | + catch(Exception ex) { |
| 75 | + return BadRequest(ex); |
| 76 | + } |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +### Bind the Blazor Grid to the Web API |
| 81 | + |
| 82 | +1. In the Blazor client project ([DxGrid.BindToDataUsingXPO](CS\DxGrid.BindToDataUsingXPO\DxGrid.BindToDataUsingXPO.csproj)), add a **DxGrid** component with multiple [DxGridDataColumn](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxGridDataColumn) objects: |
| 83 | + |
| 84 | + ```razor |
| 85 | + <DxGrid Data="GridDataSource"> |
| 86 | + <Columns> |
| 87 | + <DxGridDataColumn FieldName="@nameof(OrderDto.Id)" Width="80" /> |
| 88 | + <DxGridDataColumn FieldName="@nameof(OrderDto.OrderDate)" /> |
| 89 | + <DxGridDataColumn FieldName="@nameof(OrderDto.ExpectedDeliveryDate)" /> |
| 90 | + <DxGridDataColumn FieldName="@nameof(OrderDto.PickingCompletedWhen)" /> |
| 91 | + <DxGridDataColumn FieldName="@nameof(OrderDto.CustomerPurchaseOrderNumber)" /> |
| 92 | + <DxGridDataColumn FieldName="@nameof(OrderDto.CustomerID)" Width="120" /> |
| 93 | + </Columns> |
| 94 | + </DxGrid> |
| 95 | + ``` |
| 96 | +
|
| 97 | +1. Create a [GridDevExtremeDataSource\<T\>](https://docs.devexpress.com/Blazor/DevExpress.Blazor.GridDevExtremeDataSource-1) instance and pass an `HttpClient` along with the controller's endpoint URI. Assign the instance to the grid's **Data** property: |
| 98 | +
|
| 99 | + ```razor |
| 100 | + @code { |
| 101 | + GridDevExtremeDataSource<OrderDto>? GridDataSource { get; set; } = null; |
| 102 | +
|
| 103 | + protected override void OnInitialized() { |
| 104 | + var httpClient = ClientFactory.CreateClient("XpoApi"); |
| 105 | + var uri = new Uri(httpClient.BaseAddress!, "Orders"); |
| 106 | + GridDataSource = new(httpClient, uri); |
| 107 | + } |
| 108 | + } |
| 109 | + ``` |
| 110 | +
|
| 111 | +The grid sends requests to the Web API. The API delegates data shaping to XPO's query provider. This allows DxGrid to load only the data required for screen display instead of the entire dataset. |
| 112 | +
|
| 113 | +
|
| 114 | +## Files to Review |
| 115 | +
|
| 116 | +* [DxGrid.BindToDataUsingXPO.WebAPI - Program.cs](.\CS\DxGrid.BindToDataUsingXPO.WebAPI\Program.cs) |
| 117 | +* [DxGrid.BindToDataUsingXPO.WebAPI - Orders.cs](.\CS\DxGrid.BindToDataUsingXPO.WebAPI\Data\Orders.cs) |
| 118 | +* [DxGrid.BindToDataUsingXPO - Program.cs](CS\DxGrid.BindToDataUsingXPO\Program.cs) |
| 119 | +* [DxGrid.BindToDataUsingXPO - Index.razor](CS\DxGrid.BindToDataUsingXPO\Components\Pages\Index.razor) |
| 120 | +
|
| 121 | +## Documentation |
| 122 | +
|
| 123 | +* [XPO](https://docs.devexpress.com/XPO/2004/express-persistent-objects) |
| 124 | +* [GridDevExtremeDataSource\<T\>](https://docs.devexpress.com/Blazor/DevExpress.Blazor.GridDevExtremeDataSource-1) |
| 125 | +* [DevExtreme.AspNet.Data.DataSourceLoader](https://devexpress.github.io/DevExtreme.AspNet.Data/net/api/DevExtreme.AspNet.Data.DataSourceLoader.html) |
| 126 | +
|
| 127 | +<!-- feedback --> |
| 128 | +## Does This Example Address Your Development Requirements/Objectives? |
| 129 | +
|
| 130 | +[<img src="https://www.devexpress.com/support/examples/i/yes-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=pdf-document-api-highlight-search-results&~~~was_helpful=yes) [<img src="https://www.devexpress.com/support/examples/i/no-button.svg"/>](https://www.devexpress.com/support/examples/survey.xml?utm_source=github&utm_campaign=pdf-document-api-highlight-search-results&~~~was_helpful=no) |
| 131 | +
|
| 132 | +(you will be redirected to DevExpress.com to submit your response) |
| 133 | +<!-- feedback end --> |
0 commit comments