Reusing Expression in Linq select clause (query format) - c#

I have an Expression that converts one type of object to another type. The expression is as follows:
public Expression<Func<SQLRepository.ActionType, Model.ActionType>> DBActionTypeToActionType =
(SQLRepository.ActionType at) => new Model.ActionType()
{
ID = at.OID,
DisplayName = at.DisplayName
};
I can use the Expression like this:
var linq = (from at in dc.SQLRepositoryDC.ActionTypes select at).Select(DBActionTypeToActionType);
But I'd like to use it like this:
var linq = (from at in dc.SQLRepositoryDC.ActionTypes select DBActionTypeToActionType.Compile().Invoke(at));
I've been looking for a couple days now and I can only find references to doing this in the Where clause. It seems that if I'm able to use the function calls to do this, it should be possible using the query syntax.
The reason it is important to do use the query syntax is that some of the objects that are being selected are composed of many sub-objects and trying to chain them all of the conversions together with the function notation will be much harder to write and maintain.

It seems that if I'm able to use the function calls to do this, it should be possible using the query syntax.
That's not true. Query notation always goes via a lambda expression. For example
from x in y select z
ends up as
y.Select(x => z)
That means if you've already got an expression tree that you want to pass directly as the argument to Select, you can't use query expressions because there's this extra level of indirection.
Now the options available depend on where you need to apply the predefined expression. You can always use it in the source, and then continue with the query:
var query = from foo in dc.ActionTypes.Select(DBActionTypeToActionType)
where foo.Stuff
select foo.Other;
Or using it at the end is easy:
var query = (from bar in dc.ActionTypes
where bar.Stuff
select bar).Select(DBActionTypeToActionType);
Does that help at all?

Related

Reuse LINQ's SELECT (When querying to tables with the same signature) [duplicate]

I have an Expression that converts one type of object to another type. The expression is as follows:
public Expression<Func<SQLRepository.ActionType, Model.ActionType>> DBActionTypeToActionType =
(SQLRepository.ActionType at) => new Model.ActionType()
{
ID = at.OID,
DisplayName = at.DisplayName
};
I can use the Expression like this:
var linq = (from at in dc.SQLRepositoryDC.ActionTypes select at).Select(DBActionTypeToActionType);
But I'd like to use it like this:
var linq = (from at in dc.SQLRepositoryDC.ActionTypes select DBActionTypeToActionType.Compile().Invoke(at));
I've been looking for a couple days now and I can only find references to doing this in the Where clause. It seems that if I'm able to use the function calls to do this, it should be possible using the query syntax.
The reason it is important to do use the query syntax is that some of the objects that are being selected are composed of many sub-objects and trying to chain them all of the conversions together with the function notation will be much harder to write and maintain.
It seems that if I'm able to use the function calls to do this, it should be possible using the query syntax.
That's not true. Query notation always goes via a lambda expression. For example
from x in y select z
ends up as
y.Select(x => z)
That means if you've already got an expression tree that you want to pass directly as the argument to Select, you can't use query expressions because there's this extra level of indirection.
Now the options available depend on where you need to apply the predefined expression. You can always use it in the source, and then continue with the query:
var query = from foo in dc.ActionTypes.Select(DBActionTypeToActionType)
where foo.Stuff
select foo.Other;
Or using it at the end is easy:
var query = (from bar in dc.ActionTypes
where bar.Stuff
select bar).Select(DBActionTypeToActionType);
Does that help at all?

Difference between Query Expression and Method Expression in LINQ?

I don't know whether the term of above title is appropriate.
Just like a and b:
var list = Enumerable.Range(0, 100);
var a = from l in list
where l % 2 == 0
select l;
var b = list.Where(l => l % 2 == 0);
When should I use each of them? And any difference?
None, Query expression compiles into Method expression.
Query Syntax and Method Syntax in LINQ (C#)
Because queries return an IEnumerable, you compose them in method
syntax by chaining the method calls together. This is what the
compiler does behind the scenes when you write queries by using query syntax
Also see: LINQ Query Expressions (C# Programming Guide)
At compile time, query expressions are converted to Standard Query Operator method calls according to the rules set forth in the C#
specification. Any query that can be expressed by using query syntax
can also be expressed by using method syntax. However, in most cases
query syntax is more readable and concise. For more information, see
C# Language Specification and Standard Query Operators Overview.
Apart from that one place where I have found something that can't be done in Query expression is to get the index along with the item. For example you can do following in method syntax:
var result = list.Select((r,i) => new { value = r, index = i});
In query expression an external variable has to be defined to achieve this purpose. Here is a similar discussion with answer from Jon Skeet
No
There is no difference between them.
From Query Syntax and Method Syntax in LINQ
Because queries return an IEnumerable, you compose them in method
syntax by chaining the method calls together. This is what the
compiler does behind the scenes when you write queries by using query
syntax. And because a query variable does not store the results of the
query, you can modify it or use it as the basis for a new query at any
time, even after it has been executed.
Also from LINQ Query Expressions
At compile time, query expressions are converted to Standard Query
Operator method calls.
Query expression is transformed into standard method calls by compiler.
var a = from l in list
where l % 2 == 0
select l;
var b = list.Where(l => l % 2 == 0);
These two are exactly the same in compiled code.
However, not all methods have a keyword associated in query expression syntax.
There's no difference, it's a matter of personal preference. You can even mix the two styles if you want to.
The Linq keywords are translated into the method call syntax by the C# compiler.
The difference, in fact, is no.
In fact, it is one and the same thing, except that the expression for the $a$ the compiler converts to an expression equivalent to expression for $b$.

Modify linq query at runtime

Problem statement
Say I have a query which searches the names of people:
var result = (from person in container.people select person)
.Where(p => p.Name.Contains(some_criterion)
This will be translated to a SQL query containing the following like clause:
WHERE NAME LIKE '%some_criterion%'
This has some performance implications, as the database is unable to effectively use the index on the name column (index scan v.s. index seek if I'm not mistaken).
To remedy this, I can decide to just StartsWith() instead, generating a query using a like clause like:
WHERE NAME LIKE 'some_criterion%'
Which enables SQL server to use the index seek and delivering performance at the cost of some functionality.
I'd like to be able to provide the user with a choice: defaulting the behavior to use StartsWith, but if the user want the 'added flexibility' of searching using Contains(), than that should used.
What have I tried
I thought this to be trivial and went on and implemented an extension method on string. But of course, LINQ does not accept this and an exception is thrown.
Now, of course I can go about and use an if or switch statement and create a query for each of the cases, but I'd much rather solve this 'on a higher level' or more generically.
In short: using an if statement to differentiate between use cases isn't feasible due to the complexity of the real-life application. This would lead to alot of repetition and clutter. I'd really like to be able to encapsulate the varying behavior (Contains, StartsWith, EndsWith) somehow.
Question
Where should I look or what should I look for? Is this a case for composability with IQueryables? I'm quite puzzled!
Rather than overcomplicate things, how about just using an if statement?
var query = from person in container.people
select person;
if (userWantsStartsWith)
{
query = from p in query
where p.Name.Contains(some_criterion)
select p;
}
else
{
query = from p in query
where p.Name.StartsWith(some_criterion)
select p;
}
Update
If you really need something more complex try looking at LinqKit. It allows you to do the following.
var stringFunction = Lambda.Expression((string s1, string s2) => s1.Contains(s2));
if (userWantsStartsWith)
{
stringFunction = Lambda.Expression((string s1, string s2) => s1.StartsWith(s2));
}
var query = from p in container.people.AsExpandable()
where stringFunction.Invoke(p.Name, some_criterion)
select p;
I believe this fulfils your requirement of
I'd really like to be able to encapsulate the varying behavior
(Contains, StartsWith, EndsWith) somehow.
You can dynamically alter the query before enumerating it.
var query = container.people.AsQueryable();
if (contains)
{
query = query.Where(p => p.Name.Contains(filter));
}
else
{
query = query.Where(p => p.Name.StartsWith(filter));
}
Try dis:
var result = (from person in container.people select person)
.Where(p => some_bool_variable ? p.Name.Contains(some_criterium) : p.Name.StartsWith(some_criterium));
The real life queries are quite huge and unioned with several others. This, like my problem states, isn't te solution I'm looking for
Sinse your queries are huge: can't you just define stored procedure that handles everything and call it with specific to query parameters (probably several stored procedures that are called by main, e.g. one of em searches by Name, another - by Age, have different sort order and so on to keep code clear)?

Differences in LINQ vs Method expression

Why the Linq expression IL results in omission of the Select projection whereas the corresponding method expression keeps the Select projection ?
I suppose these two pieces of code does the same.
var a = from c in companies
where c.Length >10
select c;
//
var b = companies.Where(c => c.Length > 10).Select(c => c);
//IL - LINQ
IEnumerable<string> a = this.companies.
Where<string>(CS$<>9__CachedAnonymousMethodDelegate1);
//IL
IEnumerable<string> b = this.companies.Where<string>
(CS$<>9__CachedAnonymousMethodDelegate4).Select<string, string>
(CS$<>9__CachedAnonymousMethodDelegate5);
Then why the difference in IL?
EDITED :
then why
var a = from c in companies
select c;
result in SELECT projection even inside IL. it can also be omitted right ?
The C# compiler is clever and remove useless statement from Linq. Select c is useless so the compiler remove it. When you write Select(c=>c) the compiler can't say that's the instruction is useless because it' a function call and so it doesn't remove it.
If you remove it yourself IL become the same.
EDIT :
Linq is a "descriptive" language : you say what you want and the compiler transforms it well. You don't have any control on that transformation. The compiler try to optimize function call and don't use Select because you don't do projection so it's useless.
When you write Select(c => c) you call a function explicitely so the compiler won't remove it.
var a = from c in companies select c;
var a = c.Select(elt=>elt);
Select is usefull in this example. If you remove it a has the type of c; otherwise a is an IEnumerable
#mexianto is of course correct that this is a compiler optimization.
Note that this is explicitly called out in the language specification under "Degenerate Query expressions." Also note that the compiler is smart enough to not perform the optimization when doing so would return the original source object (the user might want to use a degenerate query to make it difficult for the client to mutate the source object, assuming that it is mutable).
7.16.2.3 Degenerate query expressions
A query expression of the form
from x in e select x
is translated into
( e ) . Select ( x => x )
[...] A degenerate query expression is one that
trivially selects the elements of the source. A later phase of the
translation removes degenerate queries introduced by other translation
steps by replacing them with their source. It is important however to
ensure that the result of a query expression is never the source
object itself, as that would reveal the type and identity of the
source to the client of the query. Therefore this step protects
degenerate queries written directly in source code by explicitly
calling Select on the source. It is then up to the implementers of
Select and other query operators to ensure that these methods never
return the source object itself.
In your second example, the call to Select is not redundant. If you would omit the Select call, the query would just return the original collection, whereas Select returns an IEnumerable.
In your first example, Where already returns an IEnumerable and the select clause doesn't do any work, so it is omitted.
Because in the query version there is no actual select projecting 'c' into something else, it is just passing on 'c' as-is. Which results in only a call to 'Where'.
In the second variation, you explicitly call 'Select' and thus do a projection. Yes, you are only returning the same objects, but the compiler will not see this.

Custom Method in LINQ to SQL query

Is it possible to use custom method In query for example:
var result = from u in context.MyTable where MyMethod(u) == 10 select u;
As Pranay explains, you cannot have a custom (C#) method as part of the LINQ to SQL query, because LINQ to SQL wouldn't be able to look at the expression tree of the method and so it cannot translate it to SQL.
One option that you have is to write your function in SQL and store it as a SQL function on the SQL Server (possibly, you could also use SQL CLR, but I have not tried that). Then you can add the function to your DataContext type and LINQ to SQL will translate it to calls to the function on SQL server. Something like:
var result = from u in context.MyTable
where context.MyMethod(u) == 10 select u;
The problem, of course, is that you'll need to write the function in SQL (I think SQL CLR could also work - not sure about the performance and other possible complications though)
I also wrote an article (some time ago) that shows how to do this when you write the "method" as an expression tree way (as a value of type Expression<Func<...>>), which is possible, because in this case, the code is compiled as an expression tree. However, there is some postprocessing that has to be done and you can still write just a single expression that can be easily inlined in the LINQ query.
Check this full article : What is and what isn't possible with linq
Following is not possible
// function used in filter
static bool MyFunc(Nwind.Product p)
{
return p.ProductName.StartsWith("B");
}
// query that uses MyFunc
var q =
from p in db.Products
where MyPriceFunc(p.UnitPrice) > 30m
select p
It compiles with no errors, but when you execute it LINQ to SQL throws an exception saying: "Static method System.Boolean MyTest(LINQTest.Nwind.Product) has no supported translation to SQL."
The exception is actually thrown when you try to fetch results from q (for example using the foreach statement), because LINQ to SQL attempts to convert the expression trees to T-SQL only when the results are needed and the query must be executed.
To fix the example you can simply copy the code that checks whether product name starts with "B" to the where clause of the query and it would work fine.
Yes, but if you are using Linq-to-Sql - your method has to have special code to handle to SQL conversion.

Categories

Resources