Evaluate constant parts of expressions in Linq

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.
 
M

Marc Gravell

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
 
A

Andrus

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.
 
J

Jon Skeet [C# MVP]

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
 
M

Marc Gravell

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
 
M

Marc Gravell

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();
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top