Closed
Description
DESCRIPTION
Sorting by an interface member from a lambda expression fails in v5.0.1. It was working before in v4.2.0.
It is beneficial to implement common sorting logic in a generic resource definition.
STEPS TO REPRODUCE
The following example code is based on your GettingStarted example. A generic resource definition that supports sorting for all models that implement an ISortable interface.
public interface ISortable
{
[Attr]
int SortOrder { get; set; }
}
[Resource]
public sealed class Book : Identifiable<int>, ISortable
{
[Attr]
public string Title { get; set; } = null!;
[Attr]
public int PublishYear { get; set; }
[HasOne]
public Person Author { get; set; } = null!;
[Attr]
public int SortOrder { get; set; }
}
public class SortableResourceDefinition<TResource> : JsonApiResourceDefinition<TResource, int>
where TResource : class, IIdentifiable<int>, ISortable
{
public SortableResourceDefinition(IResourceGraph resourceGraph)
: base(resourceGraph)
{ }
public override SortExpression? OnApplySort(SortExpression? existingSort)
{
return existingSort == null
? CreateSortExpressionFromLambda(new PropertySortOrder { (resource => resource.SortOrder, ListSortDirection.Ascending) })
: existingSort;
}
}
public class BookDefinition : SortableResourceDefinition<Book>
{
public BookDefinition(IResourceGraph resourceGraph)
: base(resourceGraph)
{ }
}
- Add the ISortable interface and update the model Book
- Add the generic resource definition and its implementation for the book resource.
- Add the resource definition service at startup.
EXPECTED BEHAVIOR
It should return an ordered collection by the property SortOrder.
ACTUAL BEHAVIOR
It raises an exception in SortExpressionLambdaConverter.cs:
{
"id": "5a2eb44b-35d7-4e5c-9299-25e5ad1cf1ef",
"status": "500",
"title": "Invalid lambda expression for sorting from resource definition. It should select a property that is exposed as an attribute, or a to-many relationship followed by Count(). The property can be preceded by a path of to-one relationships. Examples: 'blog => blog.Title', 'blog => blog.Posts.Count', 'blog => blog.Author.Name.LastName'.",
"detail": "The lambda expression 'resource => Convert(resource.SortOrder, Object)' is invalid. Type 'GettingStarted.Models.ISortable' does not exist in the resource graph."
}
Possible solution
internal sealed class SortExpressionLambdaConverter
{
private Expression? ReadAttribute(Expression expression)
{
...
- ResourceType resourceType = memberExpression.Member.Name == nameof(Identifiable<object>.Id) && memberExpression.Expression != null
- ? _resourceGraph.GetResourceType(memberExpression.Expression.Type)
- : _resourceGraph.GetResourceType(memberExpression.Member.DeclaringType!);
+ ResourceType resourceType = memberExpression.Expression != null
+ ? _resourceGraph.GetResourceType(memberExpression.Expression.Type)
+ : _resourceGraph.GetResourceType(memberExpression.Member.DeclaringType!);
...
}
}
VERSIONS USED
- JsonApiDotNetCore version: 5.0.1
- ASP.NET Core version: 6.0.6
- Entity Framework Core version: 6.0.6
- Database provider: Sqlite