Skip to content

Commit 2a99556

Browse files
authored
kb(pivotgrid): Add KB for local date aggregations and explain differences between local and XMLA binding (#2759)
* docs(pivotgrid): Explain differences between local and XMLA binding * kb(PivotGrid): Add KB for local date aggregates * Update knowledge-base/pivotgrid-local-date-aggregates.md * Update components/pivotgrid/data-binding.md
1 parent a0df573 commit 2a99556

File tree

2 files changed

+179
-3
lines changed

2 files changed

+179
-3
lines changed

components/pivotgrid/data-binding.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,22 @@ The PivotGrid supports different data sources via its `DataProviderType` paramet
2020
* [`Local`](#local) (default)
2121
* [`Xmla`](#xmla)
2222

23+
### Usage Differences
24+
25+
The available data providers differ in several ways:
26+
27+
* XMLA binding is more complex to setup, but more flexible.
28+
* Local data does not support aggregations by date periods for `DateTime` properties. If a `DateTime` property is added as a row or column, the PivotGrid will generate a separate row or column for each unique `DateTime` value. If you need [aggregations by year, month, week, and so on, then create additional `int` or `string` properties in the PivotGrid model class](slug:pivotgrid-kb-local-date-aggregates).
29+
* XMLA binding supports [load on demand](slug:pivotgrid-overview#pivotgrid-parameters), which offloads all calculations to the external data source. Local binding receives all data at once and performs all aggregate calculations in-memory. Large amounts of local data may impact the performance, especially in WebAssembly apps.
30+
* When using load on demand, XMLA binding supports custom aggregate functions that are defined and performed in the OLAP cube. Local data supports only the [predefined aggregate types in the `PivotGridAggregateType` enum](slug:telerik.blazor.pivotgridaggregatetype).
31+
* When using local data, all defined measures in `<PivotGridMeasures>` render by default in the PivotGrid. Users can uncheck and hide the measures they don't need from the [PivotGrid Configurator](slug:pivotgrid-configurator).
2332

2433
## Local
2534

26-
When bound to local data, the Pivot Grid requires its `Data` parameter to provide all the data at once as `IEnumerable<TItem>`. The component will perform all aggregate calculations in-memory and there is no [load on demand](slug:pivotgrid-overview#pivotgrid-parameters).
35+
When bound to local data, the Pivot Grid requires its `Data` parameter to provide all the data at once as `IEnumerable<TItem>`.
2736

2837
If the local data changes programmatically, you need to reset the collection instance or [call the PivotGrid `Rebind()` method](slug:pivotgrid-overview#pivotgrid-reference-and-methods). See the common documentation about [refreshing component data](slug:common-features-data-binding-overview#refresh-data) for details.
2938

30-
> Large amounts of local data may impact the performance, especially in WebAssembly applications.
31-
3239
>caption PivotGrid bound to Local data provider
3340
3441
<div class="skip-repl"></div>
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
---
2+
title: Use Date Aggregates with Local Data
3+
description: Learn how to implement and configure aggregate calculations by date periods like year, month, week, and day, when using local data binding with the Telerik PivotGrid for Blazor.
4+
type: how-to
5+
page_title: How to Use Date Aggregates with Local Data
6+
slug: pivotgrid-kb-local-date-aggregates
7+
tags: blazor, pivotgrid, aggregates
8+
ticketid: 1678109
9+
res_type: kb
10+
---
11+
12+
## Environment
13+
14+
<table>
15+
<tbody>
16+
<tr>
17+
<td>Product</td>
18+
<td>PivotGrid for Blazor</td>
19+
</tr>
20+
</tbody>
21+
</table>
22+
23+
## Description
24+
25+
This KB answers the following questions:
26+
27+
* How to allow users to aggregate local data by date periods, such as years, months, weeks, and days?
28+
* How to enable date aggregations with local PivotGrid data binding?
29+
* How to calculate date aggregates by period with a local data provider?
30+
31+
## Solution
32+
33+
The [PivotGrid supports date aggregates by period](slug:pivotgrid-data-binding#usage-differences) only with [XMLA data binding](slug:pivotgrid-data-binding#xmla). Consider the following approach for local data scenarios:
34+
35+
1. Define all `DateTime` properties in the PivotGrid model class as `internal`, `protected`, or `private`, so that the PivotGrid ignores them.
36+
1. Define additional helper properties in the PivotGrid model class, which will extract the year, month, week, and day values from the `DateTime` properties.
37+
1. Use the helper properties in the PivotGrid definition and UI.
38+
1. (optional) Use a [PivotGrid column header template](slug:pivotgrid-templates#column-header-template) to format the values of the helper properties. This may be necessary, because the PivotGrid sorts `string` values alphabetically in the column headers. In this case, you may also need to [get the correct localized value for the "TOTAL" label](slug:globalization-localization).
39+
40+
>caption Using date period aggregations in the Telerik PivotGrid for Blazor
41+
42+
````RAZOR.skip-repl
43+
@using System.Globalization
44+
@using Telerik.Blazor.Services
45+
46+
@inject ITelerikStringLocalizer TelerikStringLocalizer
47+
48+
<TelerikPivotGridContainer>
49+
50+
<TelerikPivotGridConfigurator />
51+
52+
<TelerikPivotGridConfiguratorButton />
53+
54+
<TelerikPivotGrid Data="@PivotData"
55+
DataProviderType="@PivotGridDataProviderType.Local"
56+
ColumnHeadersWidth="150px">
57+
<PivotGridColumns>
58+
<PivotGridColumn Name="@nameof(SalesModel.Year)" Title="Year" />
59+
<PivotGridColumn Name="@nameof(SalesModel.Month)" Title="Month" />
60+
<PivotGridColumn Name="@nameof(SalesModel.Week)" Title="Week" />
61+
</PivotGridColumns>
62+
<PivotGridRows>
63+
<PivotGridRow Name="@nameof(SalesModel.Category)" Title="Category" />
64+
<PivotGridRow Name="@nameof(SalesModel.Product)" />
65+
</PivotGridRows>
66+
<PivotGridMeasures>
67+
<PivotGridMeasure Name="@nameof(SalesModel.Revenue)"
68+
Title="Revenue"
69+
Format="{0:C2}"
70+
Aggregate="@PivotGridAggregateType.Sum" />
71+
</PivotGridMeasures>
72+
<ColumnHeaderTemplate>
73+
@{ var c = (PivotGridColumnHeaderTemplateContext)context; }
74+
@ConvertYearMonthString(c.Text)
75+
</ColumnHeaderTemplate>
76+
</TelerikPivotGrid>
77+
78+
</TelerikPivotGridContainer>
79+
80+
@code {
81+
private List<SalesModel> PivotData { get; set; } = new List<SalesModel>();
82+
83+
protected override void OnInitialized()
84+
{
85+
TotalSuffix = " " + TelerikStringLocalizer["PivotGrid_TotalValueFormat"].Replace("{0}", string.Empty).Trim();
86+
87+
GenerateData();
88+
}
89+
90+
/// <summary>
91+
/// Gets or sets the correct localized TOTAL string.
92+
/// </summary>
93+
private string TotalSuffix { get; set; } = " Total";
94+
95+
/// <summary>
96+
/// Convert a <c>yyyy MM</c> string to <c>MMM yyyy</c>.
97+
/// </summary>
98+
/// <param name="yearMonth">The PivotGrid column header text that will render without a template.</param>
99+
/// <returns>If the <c>yearMonth</c> argument is valid, returns a DateTime string in format <c>MMM yyyy</c> plus the optional Total suffix.
100+
/// Otherwise, return the argument as is.</returns>
101+
private string ConvertYearMonthString(string yearMonth)
102+
{
103+
string yearMonthWithoutTotal = yearMonth.Replace(TotalSuffix, string.Empty, StringComparison.InvariantCultureIgnoreCase);
104+
string totalSuffixConditional = yearMonth.Replace(yearMonthWithoutTotal, string.Empty);
105+
string[] separateYearMonth = yearMonthWithoutTotal.Split(" ");
106+
107+
if (yearMonthWithoutTotal.Length == 7 &&
108+
yearMonthWithoutTotal.IndexOf(" ") == 4 &&
109+
separateYearMonth.Length == 2)
110+
{
111+
bool yearSuccess = int.TryParse(separateYearMonth[0], NumberStyles.None, CultureInfo.InvariantCulture, out int year);
112+
bool monthSuccess = int.TryParse(separateYearMonth[1], NumberStyles.None, CultureInfo.InvariantCulture, out int month);
113+
114+
if (yearSuccess && monthSuccess)
115+
{
116+
DateTime actualDate = new DateTime(year, month, 1);
117+
118+
return $"{actualDate.ToString("MMM yyyy")} {totalSuffixConditional}";
119+
}
120+
}
121+
122+
return yearMonth;
123+
}
124+
125+
private void GenerateData()
126+
{
127+
int dataItemCount = 100;
128+
int categoryCount = 3;
129+
int productCount = 7 + 1; // effectively 7
130+
int cityCount = 3 + 1; // effectively 3
131+
int daysBack = 6 * 30;
132+
Random rnd = Random.Shared;
133+
134+
for (int i = 1; i <= dataItemCount; i++)
135+
{
136+
var productNumber = rnd.Next(1, productCount);
137+
138+
PivotData.Add(new SalesModel()
139+
{
140+
Category = $"Category {productNumber % categoryCount + 1}",
141+
Product = $"Product {productNumber}",
142+
City = $"City {rnd.Next(1, cityCount)}",
143+
ContractDate = DateTime.Today.AddDays(-rnd.Next(1, daysBack)),
144+
Revenue = rnd.Next(123, 987) * 1.23m
145+
});
146+
147+
PivotData.OrderBy(p => p.ContractDate);
148+
}
149+
}
150+
151+
public class SalesModel
152+
{
153+
public string Category { get; set; } = null!;
154+
public string Product { get; set; } = null!;
155+
public string City { get; set; } = null!;
156+
internal DateTime ContractDate { get; set; }
157+
158+
public int Year => ContractDate.Year;
159+
public string Month => ContractDate.ToString("yyyy MM");
160+
public string Week => $"Week {ISOWeek.GetWeekOfYear(ContractDate)} {ContractDate.ToString("yyyy")}";
161+
162+
public decimal Revenue { get; set; }
163+
}
164+
}
165+
````
166+
167+
## See Also
168+
169+
* [Pivot Grid Data Providers](slug:pivotgrid-data-binding)

0 commit comments

Comments
 (0)