0

In our .NET 6 project with Entity Framework Core, we use HotChocolate GraphQL 12.18.0.

To support case insensitive contains select queries on string fields, I added a custom field handler:

public class QueryableStringInvariantContainsHandler : QueryableStringOperationHandler
    {
        public QueryableStringInvariantContainsHandler(InputParser inputParser) : base(inputParser)
        {
        }

        protected override int Operation => DefaultFilterOperations.Contains;

        public override Expression HandleOperation(
            QueryableFilterContext context,
            IFilterOperationField field,
            IValueNode value,
            object parsedValue)
        {
            Expression property = context.GetInstance();
            return parsedValue is string str
                ? (Expression)Expression.NotEqual(
                        Expression.Call(
                            property,
                            typeof(string).GetMethod("IndexOf", new[] { typeof(string), typeof(StringComparison) }),
                            Expression.Constant(str),
                            Expression.Constant(StringComparison.OrdinalIgnoreCase)
                        ),
                        Expression.Constant(-1)
                    )
                : throw new InvalidOperationException();
        }
    }
public class CustomFilteringConvention : FilterConvention
    {
        protected override void Configure(IFilterConventionDescriptor descriptor)
        {
            _ = descriptor.AddDefaults();
            _ = descriptor.Operation(DefaultFilterOperations.Equals).Name("equals");
            _ = descriptor.AddProviderExtension(
                new QueryableFilterProviderExtension(x =>
                {
                    _ = x.AddFieldHandler<QueryableStringInvariantContainsHandler>();
                }));
        }
    }

In the graphql query it can be used as follows:

[...]
where: {
        or: [
          { givenName: { contains:$searchQuery}}
          { surname: { contains:$searchQuery}}
          { background: { contains:$searchQuery}}
        ]
[...]

It works fine as long as there are no null values in the database for the filtered string fields. On fields with null values in the database it fails with a null reference exception. How can I make the query work with NULL values in the database?

MatterOfFact
  • 1,253
  • 2
  • 18
  • 49
  • 1
    Show the code (classes, mappings, the code that throws the exception). Improving the question is far more useful than offering a bounty on an unanswerable question. – Gert Arnold May 11 '23 at 14:43

2 Answers2

0

I eventually found a solution by myself:

public class QueryableStringInvariantContainsHandler : QueryableStringOperationHandler
    {
        public QueryableStringInvariantContainsHandler(InputParser inputParser) : base(inputParser)
        {
        }

        protected override int Operation => DefaultFilterOperations.Contains;

        public override Expression HandleOperation(
            QueryableFilterContext context,
            IFilterOperationField field,
            IValueNode value,
            object parsedValue)
        {
            Expression property = context.GetInstance();
            return parsedValue is string str
                ? (Expression)Expression.AndAlso(
                    Expression.NotEqual(property, Expression.Constant(null, typeof(object))),
                    Expression.NotEqual(
                        Expression.Call(
                            property,
                            typeof(string).GetMethod("IndexOf", new[] { typeof(string), typeof(StringComparison) }),
                            Expression.Constant(str),
                            Expression.Constant(StringComparison.OrdinalIgnoreCase)
                        ),
                        Expression.Constant(-1)
                    )
                )
                : throw new InvalidOperationException();
        }
    }

This will also take NULL values into account

MatterOfFact
  • 1,253
  • 2
  • 18
  • 49
-1

I do not understand your question. In case of strings if you want to include nulls in the or operation you would use the eq operand:

{ stringField1: { eq:""}}