question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot perform `any` filter operation on enum collection attribute

See original GitHub issue

DESCRIPTION

Cannot filter on enum attribute. Syntax not quite clear, error misses information.

STEPS TO REPRODUCE

I have an entity Users with an attribute Role, which is an enum of [Admin, Doctor…]. In Postman, a simple GET /users will return a collection of all users.

I want to filter on Role.

I use the GET with url /users?filter=any(roles,'Admin')

In C# the roles are

        public enum Role
        {
            Admin,
            Doctor,
            Nurse,
            Assistant
        }

The user:

    public class User : Identifiable<Guid>, IManagedEntity
    {
        [Key]
        public override Guid Id { get; set; }

        [Attr]
        [Required]
        public string Email { get; set; }

        [Attr]
        public bool EmailConfirmed { get; set; }
        
        [Attr(Capabilities = AttrCapabilities.AllowChange), NotMapped]
        public string Password { get; set; }
        
        [JsonIgnore]
        public string? PasswordHash { get; set; }

        [Attr]
        public Role[]? Roles { get; set; }
    }  

EXPECTED BEHAVIOR

When I do a GET with the correct syntax for a filter on enum Role, I want to get a collection of users that has the specific Role.

ACTUAL BEHAVIOR

Postman receives an error message:

{
    "errors": [
        {
            "id": "ea9d21c3-d86f-4228-aaca-9afb124ee0da",
            "status": "400",
            "title": "The specified filter is invalid.",
            "detail": ", expected.",
            "source": {
                "parameter": "filter"
            }
        }
    ]
}

The detail field appears to be missing information.

Logging in IDE (Rider) shows:

info: JsonApiDotNetCore.Middleware.ExceptionHandler[0]
      Errors = [
        {
          "Id": "ea9d21c3-d86f-4228-aaca-9afb124ee0da",
          "Status": "400",
          "Title": "The specified filter is invalid.",
          "Detail": ", expected.",
          "Source": {
            "Parameter": "filter"
          }
        }
      ]
      JsonApiDotNetCore.Errors.InvalidQueryStringParameterException: Errors = [
        {
          "Id": "ea9d21c3-d86f-4228-aaca-9afb124ee0da",
          "Status": "400",
          "Title": "The specified filter is invalid.",
          "Detail": ", expected.",
          "Source": {
            "Parameter": "filter"
          }
        }
      ]
       ---> JsonApiDotNetCore.Queries.Internal.Parsing.QueryParseException: , expected.
         at void JsonApiDotNetCore.Queries.Internal.Parsing.QueryExpressionParser.EatSingleCharacterToken(TokenKind kind) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/Queries/Internal/Parsing/QueryExpressionParser.cs:line 85
         at EqualsAnyOfExpression JsonApiDotNetCore.Queries.Internal.Parsing.FilterParser.ParseAny() in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/Queries/Internal/Parsing/FilterParser.cs:line 204
         at FilterExpression JsonApiDotNetCore.Queries.Internal.Parsing.FilterParser.ParseFilter() in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/Queries/Internal/Parsing/FilterParser.cs:line 80
         at FilterExpression JsonApiDotNetCore.Queries.Internal.Parsing.FilterParser.Parse(string source, ResourceContext resourceContextInScope) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/Queries/Internal/Parsing/FilterParser.cs:line 42
         at FilterExpression JsonApiDotNetCore.QueryStrings.Internal.FilterQueryStringParameterReader.GetFilter(string parameterValue, ResourceFieldChainExpression scope) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/QueryStrings/Internal/FilterQueryStringParameterReader.cs:line 135
         at void JsonApiDotNetCore.QueryStrings.Internal.FilterQueryStringParameterReader.ReadSingleValue(string parameterName, string parameterValue) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/QueryStrings/Internal/FilterQueryStringParameterReader.cs:line 110
         --- End of inner exception stack trace ---
         at void JsonApiDotNetCore.QueryStrings.Internal.FilterQueryStringParameterReader.ReadSingleValue(string parameterName, string parameterValue) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/QueryStrings/Internal/FilterQueryStringParameterReader.cs:line 116
         at void JsonApiDotNetCore.QueryStrings.Internal.FilterQueryStringParameterReader.Read(string parameterName, StringValues parameterValue) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/QueryStrings/Internal/FilterQueryStringParameterReader.cs:line 78
         at void JsonApiDotNetCore.QueryStrings.Internal.QueryStringReader.ReadAll(DisableQueryStringAttribute disableQueryStringAttribute) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/QueryStrings/Internal/QueryStringReader.cs:line 61
         at async Task JsonApiDotNetCore.Middleware.AsyncQueryStringActionFilter.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/Middleware/AsyncQueryStringActionFilter.cs:line 30
         at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()+Awaited(?)
         at void Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
         at Task Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
         at Task Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
         at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextExceptionFilterAsync()+Awaited(?)

VERSIONS USED

  • JsonApiDotNetCore version: 4.2.0
  • ASP.NET Core version: net5.0
  • Entity Framework Core version: EF Core 6.4.4
  • Database provider:

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
bart-degreedcommented, Sep 12, 2021

This is by design. All filter operators act on a single value, never on arrays. How would you store an array in a database column?

The ‘equals’ function means: the target attribute must match the following constant. In contrast, the ‘set’ function means: the target attribute must match one constant from the following set, which is why you get an error when your set contains only one element – that is not a set and you should use ‘equals’ instead.

To accomplish the filter you want, don’t use an array but model roles as a to-many relationship.

public class User : Identifiable
{
    [HasMany]
    public ISet<UserRole> Roles { get; set; }
}

public class UserRole : Identifiable
{
    [Attr]
    public Role Value { get; set; }
}

Then the next filters return all users. But for each user, it includes only the subset of roles that match the condition.

GET http://localhost/users?include=roles&filter[roles]=equals(value,'Admin')

or:

GET http://localhost/users?include=roles&filter[roles]=any(value,'Doctor','Nurse')

If, on the other hand, you want to filter on users, so return only users in a specific role, use the following:

GET http://localhost/users?filter=has(roles,equals(value,'Admin'))

or:

GET http://localhost/users?filter=has(roles,any(value,'Doctor','Nurse'))
0reactions
Bezz242commented, Sep 13, 2021

Hoi Bart,

Thx for the clear explanation. I’ll take it back to the team. Roles User many-to-many makes sense.

Cheerz, Eric

Read more comments on GitHub >

github_iconTop Results From Across the Web

Not able to filter elements using an enum - java 8
I pass a list of ComputerComponent class to the averagePrice() function which has two fields of price which is of type double and...
Read more >
Filtering on an enum collection in UI for WPF
I show a collection of Dish objects in a RadGridView. As property Categories is a collection I concatenate the values into a single...
Read more >
Enum property stored as string, filter queries do not work
Entity Credit included an enum property Status , stored as a string, at the time the filter returns an "exception" as follows: System.Data....
Read more >
How to use drop down filter in list view on enum values
I want to filter out list view rows based on an enumeration value using drop down filter. I was unable to bind the...
Read more >
RadzenDataGridColumn enum filter not working without ...
I'm using a custom data grid column filter template with dropdown that is an Enum type. The filter string for LoadDataArgs looks like ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found