Evaluate constant parts of expressions in Linq

  • Thread starter Thread starter Andrus
  • Start date Start date
A

Andrus

..NET does not evaluate constant parts of expression tree.

For example,

Northwind db = CreateDB();
var q = from p in db.Products
where p.ProductName == ' '.ToString()
select p;
var l = q.ToList();

causes expression ' '.ToString() to be passed to linq driver.

How to simplify expression tree so that constant parts of expressions like

' '.ToString()

are evaluated and removed from expression tree ?

Andrus.
 
Well, *technically*, ' '.ToString() *isn't* a constant; it is the
result of invoking a virtual function on a char that returns a string.
The C# compiler will perform concatenations automatically, but I don't
think it is under any obligation to step into virtual functions.
Likewise, the LINQ expression compiler is correctly representing what
you asked it to do.

I think the best answer is: if you want it to have a string, give it a
string.

I'm guessing that your actual code does something more dynamic
(otherwise the question is mute) - in which case, simply evaluate this
first.

Marc
 
I think the best answer is: if you want it to have a string, give it a
string.

I'm guessing that your actual code does something more dynamic
(otherwise the question is mute) - in which case, simply evaluate this
first.

I have column MyCharColumn of type CHAR (single character) in database.

More presice sample:

char MyCharValue = 'X';
var q = from p in db.Products
where p.MyCharColumn == MyCharValue
select p;
var l = q.ToList();

Causes compile error.
Is this DLinq defect? It does not allow compare char column with char value
!?

To fix compile error I changed query to

var q = from p in db.Products
where p.MyCharColumn == MyCharValue.ToString()
select p;
var l = q.ToList();

but this causes runtime error in DbLinq that ToString() is not supported.

How to fix without using temporary string variable ?
How to pre-process expression tree before sql generation ?

Andrus.
 
I have column MyCharColumn of type CHAR (single character) in database.

More presice sample:

char MyCharValue = 'X';
var q = from p in db.Products
where p.MyCharColumn == MyCharValue
select p;
var l = q.ToList();

Causes compile error.
Is this DLinq defect? It does not allow compare char column with char value
!?

I suspect if you look at your model you'll find that p.MyCharColumn is
of type string, not char.
To fix compile error I changed query to

var q = from p in db.Products
where p.MyCharColumn == MyCharValue.ToString()
select p;
var l = q.ToList();

but this causes runtime error in DbLinq that ToString() is not supported.

How to fix without using temporary string variable ?

Why are you happy to use a temporary char variable but not a temporary
string variable? If your char variable is *actually* a constant
somewhere, just use constant string variables instead.
How to pre-process expression tree before sql generation ?

Well, you could write your own pre-processor, which receives an
expression tree and then returns one - you'd then pass the result into
LINQ to SQL. Once again though, it really sounds like you're trying to
work against the tool rather than with it.

Jon
 
How to fix without using temporary string variable ?
Why add stress?
How to pre-process expression tree before sql generation ?
I wouldn't recommend it; expression trees are immutable; you can re-
use them as sub-expression, but you can't re-use the outer part with a
different sub-expression. To do what you want you'd need to rebuild
the expression from the bottom up, since you'd need to change the
"invoke" expression near the bottom.
Is this DLinq defect? It does not allow compare char column with char value

Are you /sure/ the column is char? If it is actually string, and you
want to compare .SomeStringProp == someChar.ToString(), then you could
try comparing it to (as an example) LINQ-to-SQL to see if that can
handle to ToString() inline. But IIRC LINQ-to-SQL uses strings even
for char[1], so you'd need to hand crank it to test. To be honest:
speaking for myself, since there is a simple and obvious workaround I
really wouldn't bother checking...

[...]

To second Jon's answer, I'd be pragmatic here...

char MyCharValue = 'X'; // from where-ever
string s = MyCharValue.ToString();

var q = from p in db.Products
where p.MyCharColumn == s
select p;
var l = q.ToList();

Job done; then I'd move on to the next problem...

Marc
 
More presice sample: [snip] Causes compile error.

Just to prove that the expression compiler isn't at fault here; please
double-check your column type. The compiler is perfectly happy. It is
quite possible that when you get the expression right, that DbLinq
will be happy with it without the ToString(); in fact - if I *add*
the .ToString(), then the compiler spots it and complains.

class Product {
public char MyCharColumn { get; set; }
}
class DatabaseMock {
public IQueryable<Product> Products {
// only need it to compile... doesn't need to work...
get { throw new NotImplementedException(); }
}
}
static class Program {
static void Main() {
var db = new DatabaseMock();

char MyCharValue = 'X';
var q = from p in db.Products
where p.MyCharColumn == MyCharValue
select p;
var l = q.ToList();
}
}
 
Back
Top