Skip to content

Instantly share code, notes, and snippets.

@mrpmorris
Created October 13, 2022 15:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrpmorris/2da068102946df590f28020023086654 to your computer and use it in GitHub Desktop.
Save mrpmorris/2da068102946df590f28020023086654 to your computer and use it in GitHub Desktop.
OData sorting / filtering from Blazor TelerikGrid through to the server
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();
}
}
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)));
}
}
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