Skip to content

Cannot sort resource having a relationship with EagerLoadAttribute #988

Closed
@ThomasBarnekow

Description

@ThomasBarnekow

DESCRIPTION

Before describing my issue, let me first thank you for this project. It is absolutely awesome.

On to my issue. I have a resource called Engagement with several HasMany relationships. Three of those are related in the following way: The first one, Parties, is the navigation property in an EF core relationship between Engagement and EngagementParty (where one engagement can have many engagement parties). The other two, FirstParties and SecondParties, are NotMapped from an EF Core perspective and derived from Parties by selecting a subset of the elements contained in Parties. Based on your documentation, I've added the EagerLoad attribute to the Parties relationship. This also works, meaning that I can GET the FirstParties and SecondParties. However, what does not work is sorting the EngagementParty resources by any of their attributes (e.g., ShortName). For example:

GET http://localhost:5000/engagements/2a65799a-12f6-4392-e88d-08d8f511af45/parties

produces the same order as

GET http://localhost:5000/engagements/2a65799a-12f6-4392-e88d-08d8f511af45/parties?sort=shortName

which produces the same order as

GET http://localhost:5000/engagements/2a65799a-12f6-4392-e88d-08d8f511af45/parties?sort=-shortName

When I remove the EagerLoad attribute from the Parties relationship, the resources can be sorted as expected.

The same restriction/issue applies to sort orders applied by resource definitions (in the OnApplySort() method). With EagerLoad, the sort order has no effect. Without EagerLoadthe sort order is applied correctly.

STEPS TO REPRODUCE

Here are the Engagement and EngagementParty entities. Note the EagerLoad attribute on the Parties property.

    public class Engagement : EntityBase<Guid>
    {
        // Data

        [Attr]
        public string Name { get; set; }

        // Navigation Properties

        [HasMany]
        public ICollection<DocumentType> DocumentTypes { get; set; } = new List<DocumentType>();

        [HasMany]
        [EagerLoad]
        public ICollection<EngagementParty> Parties { get; set; } = new List<EngagementParty>();

        [HasMany]
        [NotMapped]
        public ICollection<EngagementParty> FirstParties =>
            Parties.Where(p => p.Role == ModelConstants.FirstParty).OrderBy(p => p.ShortName).ToList();

        [HasMany]
        [NotMapped]
        public ICollection<EngagementParty> SecondParties =>
            Parties.Where(p => p.Role == ModelConstants.SecondParty).OrderBy(p => p.ShortName).ToList();
    }

    public class EngagementParty : EntityBase<Guid>
    {
        // Foreign Keys (simplified)

        public Guid EngagementId { get; set; }

        [HasOne]
        public Engagement Engagement { get; set; }

        // Data (simplified)

        [Attr]
        public string Role { get; set; }

        [Attr]
        public string ShortName { get; set; }
    }

    public abstract class EntityBase<TId> : Identifiable<TId>
    {
        public DateTimeOffset? DateCreated { get; set; }

        public DateTimeOffset? DateModified { get; set; }

        [Timestamp]
        public byte[] RowVersion { get; set; }
    }

Here is the resource definition that establishes a default sort order:

    public class EngagementPartyResourceDefinition : JsonApiResourceDefinition<EngagementParty, Guid>
    {
        /// <inheritdoc />
        public EngagementPartyResourceDefinition(IResourceGraph resourceGraph) : base(resourceGraph)
        {
        }

        /// <inheritdoc />
        public override SortExpression OnApplySort(SortExpression? existingSort)
        {
            if (existingSort != null)
            {
                return existingSort;
            }

            return CreateSortExpressionFromLambda(new PropertySortOrder
            {
                (ep => ep.Role, ListSortDirection.Ascending),
                (ep => ep.ShortName, ListSortDirection.Ascending)
            });
        }
    }

It is registered in the Startup class as follows:

    services.AddScoped<IResourceDefinition<EngagementParty, Guid>, EngagementPartyResourceDefinition>();

With the EagerLoad attribute, sorting does not work. When removing the EagerLoad attribute, sorting works as expected.

EXPECTED BEHAVIOR

Sorting works with the EagerLoad attribute applied to the Parties relationship property.

ACTUAL BEHAVIOR

Sorting does not work with the EagerLoad attribute applied to the Parties relationship property.

VERSIONS USED

  • JsonApiDotNetCore version: 4.1.1
  • ASP.NET Core version: 5.0
  • Entity Framework Core version: 5.0
  • Database provider: MSSQLLocalDB (SQL Server 13.0.4001)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions