Why don't the usual laws in the calculation of a logical expression fit into LINQ?

In this code:

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

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

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

the entire expression section is evaluated regardless of the type of insurance NumberSearch is null or non-null.

I am using LINQ to NHibernate

UPDATE:

Unfortunately, I was mistaken in the first fragment. Right:

 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 the above, when insuranceNumberSearch null , the remaining expressions are no longer evaluated. If this behavior does not exist, insuranceNumberSearch.Trim() will cause the referenced object to be a NULL exception. Sadly LINQ (or perhaps LINQ-to-NHibernate) does not obey this pleasant behavior and evaluates all expressions, even when insuranceNumberSearch is null and leads to an error.

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

+4
source share
3 answers

Hit me but you would not use

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

in your statement, whether in a LINQ expression or not?

+5
source

As shown in this code, this is not a LINQ 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 is possible that the expression evaluator for LINQ to NHibernate does not perform conditional segment operations like LINQ to Objects does.

Program Output:

 Checking if One contains O One null 

Keep in mind that LINQ is a way of representing arbitrary expressions for conversion to other syntaxes. As far as I understand, LINQ itself would not appreciate the expression, NHibernate (whatever that is). Therefore, LINQ simply converts the expression you provide into an expression compatible with NHibernate. If NHibernate does not have a means of representing conditional shortcut operations, I can present one of three things:

  • NHibernate will evaluate the expression in its own way (just as LINQ to SQL will always abbreviate AND operations, even if you use AND operators without binding from VB.NET).
  • You will receive an error message that the expression cannot be represented in NHibernate syntax.
  • Only a limited portion of the request will be converted to NHibernate syntax; the rest will be evaluated using LINQ to Objects.
+3
source

It seems that the problem is that the NHibernate provider for LINQ is for LINQ for objects (which simply parses requests into method calls), the law will act as expected. The problem is that when working with expression trees, the provider can make any changes to your code.

What could be worse - the target runtime may not support the exact semantics of some C # operations. For example, it may not have the same implementation of floating point arithmetic.

In your example, NHibernate does not seem to support short circuit behavior. I don’t understand why this will be a problem - he can evaluate the second part of the expression, but the result should be the same.

In any case, if the short-circuit statements cause problems for the supplier, you may have to split the request into two:

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

Source: https://habr.com/ru/post/1301953/


All Articles