Created
October 13, 2022 15:14
-
-
Save mrpmorris/2da068102946df590f28020023086654 to your computer and use it in GitHub Desktop.
OData sorting / filtering from Blazor TelerikGrid through to the server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using MyApp.Contracts; | |
using Community.OData.Linq; | |
using Microsoft.EntityFrameworkCore; | |
namespace CarePlace.AppLayer.Persistence; | |
internal static class IQueryableExtensions | |
{ | |
public static IQueryable<T> ApplyODataParameters<T>( | |
this IQueryable<T> source, | |
ODataQueryParameters parameters, | |
int maxResults, | |
string defaultOrdering) | |
{ | |
if (parameters is null) | |
parameters = new ODataQueryParameters(); | |
int skip = Math.Max(0, parameters.Skip); | |
var top = Math.Min(maxResults, parameters.Top); | |
if (top < 1) | |
top = 1; | |
string orderBy = string.IsNullOrWhiteSpace(parameters.OrderBy) | |
? defaultOrdering | |
: parameters.OrderBy; | |
string? filter = parameters.Filter; | |
var result = source.OData(); | |
if (!string.IsNullOrWhiteSpace(filter)) | |
result = result.Filter(filter); | |
if (!string.IsNullOrWhiteSpace(orderBy)) | |
result = result.OrderBy(orderBy); | |
return result | |
.Skip(skip) | |
.Take(top); | |
} | |
public static Task<int> ODataCountAsync<T>(this IQueryable<T> source, ODataQueryParameters parameters) | |
{ | |
if (parameters is null) | |
throw new ArgumentNullException(nameof(parameters)); | |
var result = source.OData(); | |
if (!string.IsNullOrEmpty(parameters.Filter)) | |
result = result.Filter(parameters.Filter); | |
return result.CountAsync(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Globalization; | |
using System.Web; | |
namespace MyApp.Contracts; | |
public class ODataQueryParameters | |
{ | |
public int Top { get; set; } = 10; | |
public int Skip { get; set; } | |
public string? Filter { get; set; } | |
public string? OrderBy { get; set; } | |
public static ODataQueryParameters ParseODataQueryString(string oDataQueryString) | |
{ | |
Func<string, string> transformValue = x => HttpUtility.UrlDecode(x); | |
IEnumerable<KeyValuePair<string, string>> keysAndValues = | |
(oDataQueryString ?? "").Split('&') | |
.Where(x => x.IndexOf('=') >= 0) | |
.Select(x => Split(x, transformValue)); | |
return new ODataQueryParameters(keysAndValues); | |
} | |
public ODataQueryParameters() { } | |
private ODataQueryParameters(IEnumerable<KeyValuePair<string, string>> keysAndValues) | |
{ | |
int top = int.MaxValue; | |
int skip = 0; | |
foreach (var keyAndValue in keysAndValues) | |
{ | |
if (string.Equals(keyAndValue.Key, "$top", StringComparison.InvariantCultureIgnoreCase)) | |
int.TryParse(keyAndValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out top); | |
if (string.Equals(keyAndValue.Key, "$skip", StringComparison.InvariantCultureIgnoreCase)) | |
int.TryParse(keyAndValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out skip); | |
if (string.Equals(keyAndValue.Key, "$filter", StringComparison.InvariantCultureIgnoreCase)) | |
Filter = keyAndValue.Value; | |
if (string.Equals(keyAndValue.Key, "$orderby", StringComparison.InvariantCultureIgnoreCase)) | |
OrderBy = keyAndValue.Value; | |
} | |
Top = top; | |
Skip = skip; | |
if (string.IsNullOrWhiteSpace(OrderBy)) | |
OrderBy = ""; | |
if (string.IsNullOrWhiteSpace(Filter)) | |
Filter = ""; | |
} | |
private static KeyValuePair<string, string> Split(string value, Func<string, string> transformValue) | |
{ | |
if (transformValue is null) | |
transformValue = x => x; | |
int index = value.IndexOf('='); | |
return new KeyValuePair<string, string>( | |
key: value.Substring(0, index), | |
value: transformValue(value.Substring(index + 1))); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public async Task<MyEntitySearchResponse> Handle(MyEntitySearchQuery request, CancellationToken cancellationToken) | |
{ | |
var query = MyEntityRepository | |
.Query() | |
.ProjectTo<MyEntityDto>(AutoMapper.ConfigurationProvider); | |
MyEntityDto[] MyEntitys = await query | |
.ApplyODataParameters( | |
parameters: request.ODataQuery, | |
maxResults: 100, | |
defaultOrdering: nameof(MyEntityListItemModel.Name)) | |
.ToArrayAsync(cancellationToken); | |
int count = await query.ODataCountAsync(request.ODataQuery); | |
return new MyEntitySearchResponse(MyEntitys, count); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment