Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why ordinary laws in evaluating boolean expression does not fit into LINQ?

In such a code:

if (insuranceNumberSearch == null 
     ? true  
     : ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim())) 
   doSomething();

where insuranceNumberSearch is null, remaining expression is not null while in following code:

var q = from ei in session.Linq<EmployeeInsurance>()
        where insuranceNumberSearch == null 
                ? true 
                : ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim())
        select ei;

all section of expression is evaluated regardless of insuranceNumberSearch is null or is not null.

I'm using LINQ to NHibernate

UPDATE:

Unfortunately I have put the first snippet wrong. The correct is:

if (insuranceNumberSearch == null || (insuranceNumberSearch != null && ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim()))
doSomething();

or

bool b1 = insuranceNumberSearch == null ? true : ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim());
if (b1)
doSomething();

In both of above when insuranceNumberSearch is null, remaining expressions are not evaluated any more. If such a behavior does not exists, insuranceNumberSearch.Trim() will cause a reference object is null exception. Sadly LINQ (or maybe LINQ-to-NHibernate) does not obey such a nice behavior and evaluate all of expression even when insuranceNumberSearch is null and results in error.

UPDATE 2: I found a similar question: The || (or) Operator in Linq with C#

like image 568
Afshar Mohebi Avatar asked Dec 30 '22 01:12

Afshar Mohebi


2 Answers

Beat me, but wth wouldn't you use

if (
     (insuranceNumberSearch == null) ||
     ei.InsuranceNumber.Contains(insuranceNumberSearch.Trim()))
  doSomething();

in your statement, be it in the LINQ expression or not?

like image 92
Benjamin Podszun Avatar answered Jan 01 '23 15:01

Benjamin Podszun


As demonstrated by this code, it's not LINQ's problem. This code is similar to yours, but it does not evaluate both sides of the condition in the LINQ expression:

class Program
{
  class MyClass
  {
     public string value;
     public MyClass(string value) { this.value = value; }
     public bool Contains(char elem)
     {
        Console.WriteLine("Checking if {0} contains {1}", value, elem);
        return value.Contains(elem);
     }
  }

  static void Main(string[] args)
  {
     var mc = new MyClass[2];
     mc[0] = new MyClass("One");
     mc[1] = new MyClass(null);
     var q = from i in mc where i.value == null ? true : i.Contains('O') select i;
     foreach (MyClass c in q)
        Console.WriteLine(c.value == null ? "null" : c.value);
  }
}

It's possible the expression evaluator for LINQ to NHibernate does not perform shotcut conditional operations the way LINQ to Objects does.

The output of the program is:

Checking if One contains O
One
null

Keep in mind that LINQ is a way of representing arbitrary expressions for conversion into other syntaxes. As I understand it, LINQ itself would not evaluate the expression, NHibernate would (whatever that is). So LINQ just converts the expression you provide into an expression compatible with NHibernate. If NHibernate doesn't have a means of representing shortcut conditional operations, I can imagine one of 3 things occurring:

  1. NHibernate will evaluate the expression its own way (just like LINQ to SQL will always shortcut AND operations even if you use the non-shortcutting AND operator from VB.NET).
  2. You'll get an error that the expression can't be represented in NHibernate syntax.
  3. Only a limited portion of the query will be converted to NHibernate syntax; the rest will be evaluated by LINQ to Objects.
like image 32
BlueMonkMN Avatar answered Jan 01 '23 16:01

BlueMonkMN