System.Linq.Dynamic.Core icon indicating copy to clipboard operation
System.Linq.Dynamic.Core copied to clipboard

Where(List.Any(Field in @0), params) causes ParseException: '')' or ',' expected'

Open pierrebelin opened this issue 4 years ago • 1 comments

1. Description

Expression "Where" seems to not working with params in this kind of case : Where(List.Any(Field in @0), params)

2. Exception

Exception message: System.Linq.Dynamic.Core.Exceptions.ParseException: '')' or ',' expected'

Stack trace:    at System.Linq.Dynamic.Core.Tokenizer.TextParser.ValidateToken(TokenId t, String errorMessage)
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseArgumentList()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseEnumerable(Expression instance, Type elementType, String methodName, Int32 errorPos, Type type)
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseMemberAccess(Type type, Expression expression)
   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()
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.Parse(Type resultType, Boolean createParameterCtor)
   at System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(Type delegateType, ParsingConfig parsingConfig, Boolean createParameterCtor, ParameterExpression[] parameters, Type resultType, String expression, Object[] values)
   at System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(ParsingConfig parsingConfig, Boolean createParameterCtor, ParameterExpression[] parameters, Type resultType, String expression, Object[] values)
   at System.Linq.Dynamic.Core.DynamicExpressionParser.ParseLambda(ParsingConfig parsingConfig, Boolean createParameterCtor, Type itType, Type resultType, String expression, Object[] values)
   at System.Linq.Dynamic.Core.DynamicQueryableExtensions.Where(IQueryable source, ParsingConfig config, String predicate, Object[] args)
   at System.Linq.Dynamic.Core.DynamicQueryableExtensions.Where[TSource](IQueryable`1 source, ParsingConfig config, String predicate, Object[] args)
   at System.Linq.Dynamic.Core.DynamicQueryableExtensions.Where[TSource](IQueryable`1 source, String predicate, Object[] args)
   at SecConfigModel.TDD.TDDDynamicLinqBug.GetEntityFilters_TestIn() in TDDDynamicLinqBug.cs:line 102

3. Fiddle or Project

Here is what I used to reproduce the bug : I have 2 classes : Organization and Site. An organization contains a list for sites. Site only contains a name. I wrote couple of way to access to the data, and at the end, the one which doesn't work.

[Fact]
public void GetEntityFilters_TestIn()
{
    //public class Organization
    //{
    //    public ICollection<Site> Sites { get; set; }
    //}

    //public class Site
    //{
    //    public string Code { get; set; }
    //}

    //var organizations = new List<Organization>()
    //{
    //    new()
    //    {
    //        Code = "OrganizationA",
    //        Sites = new List<Site>()
    //        {
    //            new()
    //            {
    //                Code = "SiteNorth1",
    //            },
    //            new() {
    //                Code = "SiteNorth2",
    //            }
    //        }
    //    },
    //    new()
    //    {
    //        Code = "OrganizationB",
    //        Sites = new List<Site>()
    //        {
    //            new()
    //            {
    //                Code = "SiteNorth3",
    //            },
    //            new() {
    //                Code = "SiteNorth4",
    //            }
    //        }
    //    },
    //    new()
    //    {
    //        Code = "OrganizationC",
    //        Sites = new List<Site>()
    //        {
    //            new()
    //            {
    //                Code = "SiteNorth1",
    //            },
    //            new() {
    //                Code = "SiteNorth5",
    //            }
    //        }
    //    }
    //};


    var siteFilters = new List<string>() { "SiteNorth1", "SiteNorth5" };

    // Working by accessing directly code from sites
    var test1 = _dbContext.Sites.Where("Code in @0", siteFilters);

    // Working by accessing from organizations with predicate params for an equal expression
    var test2 = _dbContext.Organizations.Where("Sites.Any(Code = @0)", siteFilters.First());

    // Working by accessing from organizations with classic LINQ
    var test3 = _dbContext.Organizations.Where(_ => _.Sites.Any(_ => siteFilters.Contains(_.Code)));

    // Working by accessing from organizations with string predicate
    var test5 = _dbContext.Organizations.Where("Sites.Any(Code in (\"SiteNorth1\", \"SiteNorth5\"))");

    // Not working : error : System.Linq.Dynamic.Core.Exceptions.ParseException: '')' or ',' expected'
    var test6 = _dbContext.Organizations.Where("Sites.Any(Code in @0)", siteFilters);
}

4. Any further technical details

If you need any information, I'll be glad to help ! Regards

pierrebelin avatar Sep 04 '21 12:09 pierrebelin

When using your code and a simple Queryable, it works fine.

Please see this PR for details: https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/761

StefH avatar Dec 05 '23 18:12 StefH