How to use expression with null field with mongo

Viewed 239

good day i have issue with mongo db and linq. for example: i have Order class:

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

each order belong to one of factory (via FactoryId field)

now i have current user:

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

user can linked to factory or can be system wide (acess to all factories, so Factory is null)

now, i wan to getl all orders which current user can access to:

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

and if current user have not factory (factory = null) then i got exception: System.Reflection.TargetException: Non-static method requires a target.

with stack trace:

   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 45

i create sample for reproduce this behaviour: https://dotnetfiddle.net/iFIkrA

if i change user to user that bounded to factory - all work fine

so i don't understand what i missed

i used .net core 3.1 with mongodb.driver 2.10.4

1 Answers

This happens because you are trying to access the property of a null object:

x.FactoryId == currentUser.Factory.Id

So to solve this problem we can check if property Factory is null and if it is then set some other value that will not be found in the database like -1 and if it is other than null then we can assign its Id. Example below:

        var currentUser = new User();
        var factoryId = currentUser.Factory == null ? -1 : currentUser.Factory.Id;
        //Now exception should not be thrown
        var orders = db
            .GetCollection<Order>("orders").AsQueryable()
            .Where(x => currentUser.Factory == null || 
                   x.FactoryId == factoryId)
            .ToArray();
Related