What is the difference between these 2 LINQ queries? - c#

I have 2 LINQ queries, one returns what I expect, the other doesn't and i'm trying to understand why. I'm trying to figure out if from all the nodes in Config, is there a node that is called "TEST" and its Selected attribute is True.
Query 1 - Which returns the right thing has the condition inside Any():
var res1 =
(from config in _config.CurrentSettings.Config let name = config.name select config).Any(
config => config.name.Equals("TEST") && config.selected == true);
Query 2, which fails, has the condition inside Select:
(_config.CurrentSettings.Config.Select(config => config.name.Equals("TEST") && config.selected))
.Any();

LINQ's Any() with no condition means "has at least one row". The first query specifies a condition, making it "has at least one row matching the condition".
To make the second query equivalent to first one, use Any(flag => flag), or replace Select with Where. Both these options are inferior to the initial Any, with the condition inside, because they are not as readable.

The whole thing here is useless.
(from config in _config.CurrentSettings.Config let name = config.name select config)
You can narrow it down to this
_config.CurrentSettings.Config.Any(config => config.name.Equals("TEST") && config.selected == true);
Which will perform same as your first block of code.
The Select methods converts an ienumerable into another form using a selector
you give.
parameter-less Any returns true if sequence contains any element. otherwise returns false.

You may want to try:
var isTestSelected = _config.CurrentSettings.Config.Any(config => config.name.Equals("TEST") && config.selected);
Looking at the documentation for the Select and Any methods, may provide some insight.
If you look at the Parameters section of each of those links, you'll see that while both methods accept a Func, their usage is actually different.
Any
predicate
Type: System.Func<TSource, Boolean> A function to test each
element for a condition.
Select
selector
Type: System.Func<TSource, TResult> A transform function to
apply to each element.
So, in your Query1 example, you're applying a transform (or map) to each item in your collection, which declares a local name variable
let name = config.name (which is not being used), and then just returns the object as is (without actually transforming anything) select config. This bit of code is superfluous, and can be removed.
Your Any() lambda is doing all the work in Query1, by filtering items that don't match your lambda predicate.
In Query2, you're passing a filtering lambda to a transform function, and then using a filtering function without a filter.
There are many different ways to get your desired result using Linq. I encourage you to look at the different mapping (selector) and filtering (predicate) functions provided by the framework (link).

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?

Trying to sort IQueryable by dynamic properties

I have the following problem that I would like to solve with a single Linq Query:
I have my data in a database which I retrieve with the help of Entity Framework's Linq to SQL, then I would like to apply a sorting. For this I have a simple string I get from the client which I then map to a property dynamically. After that I only get the chunk I need to display via a simple Skip and Take.
The problem now seems to be that the actions I try to apply don't really go together well. I use an IQueryable for the Linq result since I get my data from the database. As soon as the Linq query tries to execute I get the error that with Linq to SQL I cannot use "ToValue()" which I need to do my dynamical sorting like this:
x.GetType().GetProperty(propertyName).GetValue(x, null);
Is what I'm trying to do even possible and can someone point me in the right direction? I've been playing around for what seems like forever with different approaches, but to no avail.
This is my last approach with some variables hardcoded, but it doesn't work either (and it might be clunky, since I've been working on it for some time now).
IQueryable<OA_FileUpload> result;
Expression<Func<MyObject, object>> orderBy = x => x.GetType().GetProperty(propertyName).GetValue(x, null);
result = Db.MyObject.Where(f => f.isSomething == true && f.isSomethingElse == false)
.OrderBy(orderBy)
.Skip(20)
.Take(20);
As soon as I later try to do something with the result it fails completely.
No it is not possible in the way you're trying. The Entity Framework's engine cannot translate x.GetType().GetProperty(propertyName).GetValue(x, null); to SQL. You're applying OrderBy before Skip and Take, which is the right way, but it also means that your sorting will be translated as part of the generated SQL.
What you can do though, is to build your query inclemently (i.e. in several steps). Then you can add the sorting with the conditions you want. Something like this:
IQueryable<OA_FileUpload> result =
Db.MyObject.Where(f => f.isSomething == true && f.isSomethingElse == false);
//Add your conditional sorting.
if(...) //Your first condition for sorting.
result = result.OrderBy(....); //Your sorting for that condition.
else if(...) //Your second condition for sorting.
result = result.OrderBy(....); //Your sorting for that condition.
//Now apply the paging.
result = result.Skip(20).Take(20);
The LINQ above is still translated into and executed as one single query, but now you can add all the conditions you want.

How to order a collection property using Linq?

Periods is a collection containing properties 'periodStart' and 'periodEnd' for each Period.
I need to order the grid by the value of the last 'periodEnd' of each Period.
I thought that the code below would work, ...
var result = from sched in schedles
orderby sched.Periods.Last().periodEnd descending
select new Grid
{
ID = sched.ID,
Name = sched.Name
};
but instead I get the error -->
Message: LINQ to Entities does not recognize the method '... Last[Period](System.Collections.Generic.IEnumerable`1[... Period])'
method, and this method cannot be translated into a store expression.
I'm sure this is a simple issue for the more advanced developers, but I know I'm missing some piece of understanding.
Thanks in advance to anyone who can help me understand the limitations of this orderby statement.
There is a host of common LINQ methods that are not supported by LINQ to Entities. Last() is one of them. If instead you use First() you will get
The method 'First' can only be used as a final query operation.
So you should do
orderby sched.Periods.OrderByDescending(p => p.periodEnd)
.FirstOrDefault().periodEnd
You must order the Periods by some property to tell EF what "first" is. You can use FirstOrDefault() without guarding against null reference exceptions, because the whole expression is translated into SQL. it's not executed as in-memory LINQ.
If I understand your question correctly, I believe this will get the result you want:
var result = schedles.OrderByDescending(x => x.periodEnd).Select(new Grid
{
ID = sched.ID,
Name = sched.Name
});

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.

Reusing Expression in Linq select clause (query format)

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?

Categories

Resources