Search code examples
c#linqentity-framework-coredynamic-linqef-core-6.0

Using the LIKE operator in Dynamic LINQ


Note: If you have the same problem and found this question before the "duplicated" one, be aware that the answer to that question does not work. I marked the only working solution below.

I'm trying to follow this guide which states that this should be possible in Dynamic LINQ:

var config = new ParsingConfig { ResolveTypesBySimpleName = true };
var example2 = Cars.Where(config, "DynamicFunctions.Like(Brand, \"%t%\")");
example2.Dump();

I'm using string concatination to build a complex query:

IQueryable<DtcViewEntity> queryable = ...
string[] values = { "%a%" };
string myOperator = "and"; // or sometimes "or"
bool isNot = false; // or sometimes "true"

var query = string.Join($" {myOperator} ", values.Select((value, index) => $"DynamicFunctions.Like(MyColumn, @{index})"));
if (isNot)  query = $"not ({query})";
var config = new ParsingConfig { ResolveTypesBySimpleName = true };
return queryable.Where(config, query, values);

But the actual error can be reproduced with code that looks almost identical to the example in the guide:

IQueryable<DtcViewEntity> queryable = ...

var config = new ParsingConfig { ResolveTypesBySimpleName = true };
var result = queryable.Where(config,  "DynamicFunctions.Like(MyColumn, \"%a%\")").ToList();

And I get:

System.Linq.Dynamic.Core.Exceptions.ParseException : Enum type 'DynamicFunctions' not found
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseAsEnum(String id)
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseMemberAccess(Type type, Expression expression)
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseIdentifier()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParsePrimaryStart()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParsePrimary()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseUnary()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseMultiplicative()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseAdditive()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseShiftOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseComparisonOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseLogicalAndOrOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseIn()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseAndOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseOrOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseLambdaOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseNullCoalescingOperator()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseConditionalOperator()

I've seen this code as well, but using var config = ParsingConfig.DefaultEFCore21; will result in

System.Linq.Dynamic.Core.Exceptions.ParseException : Enum type 'DynamicFunctions' not found
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseAsEnum(String id)
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseMemberAccess(Type type, Expression expression)
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseIdentifier()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParsePrimaryStart()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParsePrimary()

After adding Microsoft.EntityFrameworkCore.DynamicLinq to the dependencies I get:

System.Linq.Dynamic.Core.Exceptions.ParseException : No applicable method 'Like' exists in type 'DynamicFunctions'

Falco Alexander even found a "working example" form ZZZ Projects that produces the very same error message:

Unhandled exception. Enum type 'DynamicFunctions' not found (at index 21)
Command terminated by signal 6

I can't find any information on this exception, so my question is: what am I doing wrong?


Solution

  • Get Extension methods from this answer. It contains GetItemsPredicate function, which will help in building predicate.

    Then we can generate needed predicate without Dynamic.Linq and avoid raw text parsing.

    
    // input parameters
    string[] values = { "%a%" };
    var isOr = true;
    var isNot = false;
    
    var predicate = queryable.GetItemsPredicate(values, (e, v) => EF.Functions.Like(e.MyColumn, v), isOr);
    
    if (isNot)
    {
        // inversion
        predicate = Expression.Lambda<Func<DtcViewEntity, bool>>(Expression.Not(predicate.Body), predicate.Parameters);
    }
    
    // applying generated predicate
    queryable = queryable.Where(predicate);