Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-3140

PartialEvaluator should not evaluate unnecessary clauses for AndAlso, Conditional and OrElse

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 2.15.1
    • Affects Version/s: 2.10.4, 2.11.0-beta2
    • Component/s: Linq, LINQ3
    • Environment:
      .net core 3.1

      I found case then LINQ filter fail with exception if one of expression member is null.

      For example we have orders which bounded to factory (view FactoryId field):

      class Order
      {    
          public int Id {get;set;}
          public int FactoryId {get;set;}
       
       }
       

      We have current user, each user can be bound to factory or can be system wide (factory = null):

      class User
      {    
          public int Id {get;set;}
          public Factory Factory {get;set;}
      }
      
      class Factory
      {
          public int Id {get;set;}
      }
      

      Now i want to get all orders which current user can access to:

      var orders = db
          .GetCollection<Order>("order1").AsQueryable()
          .Where(x => currentUser.Factory == null || x.FactoryId == currentUser.Factory.Id);
      

      In case of system wide user (currentUser.Factory = null) i get exception of type System.Reflection.TargetException: Non-static method requires a target with following stacktrace:

      System.Reflection.TargetException: Non-static method requires a target.
       at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
       at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
       at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
       at System.Reflection.PropertyInfo.GetValue(Object obj)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.ReflectionEvaluator.VisitMember(MemberExpression node)
       at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.ReflectionEvaluator.Evaluate(Expression node)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.EvaluateSubtree(Expression subtree)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.Visit(Expression node)
       at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
       at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.Visit(Expression node)
       at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
       at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.Visit(Expression node)
       at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
       at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.Visit(Expression node)
       at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
       at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.Visit(Expression node)
       at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
       at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
       at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
       at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.Visit(Expression node)
       at MongoDB.Driver.Linq.Processors.PartialEvaluator.Evaluate(Expression node)
       at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Prepare(Expression expression)
       at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Translate(Expression expression)
       at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Execute(Expression expression)
       at MongoDB.Driver.Linq.MongoQueryableImpl`2.GetEnumerator()
       at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
       at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
       at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
       at ConsoleApp1.Program.Main(String[] args) in D:\ConsoleApp1\ConsoleApp1\Program.cs:line 56
      

      If current user bounded to factory all work fine.

      i try to rewrite to condition operator:

      var orders = db
          .GetCollection<Order>("order1").AsQueryable()
          .Where(x => currentUser.Factory == null ? true : x.FactoryId == currentUser.Factory.Id)
      

      But with no luck - IIF operator does not work.

      I create fiddle with sample code that reproduce this behaviour: https://dotnetfiddle.net/iFIkrA

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            anatoly.kryzhanovsky@singularis-lab.com Анатолий Крыжановский
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: