Why is the "Select" of a Method Syntax is in another parenthesis? - linq

var sample = db.Database.OrderByDescending(x => x.RecordId).Select(y => y.RecordId).FirstOrDefault();
I don't know if my title is correct / right. Just want to ask why this query the select is in another ( )?. As for the example .Select(y => y.RecordId) unlike the query I use to be
var sample = (from s in db.Databse where s.RecordId == id select s) I know this is the same right?. Then what is the why it is in another parenthesis?. Anyone has an idea or can anyone explain it why?. Thanks a lot.

In your first example, you're using "regular" C# syntax to call a bunch of extension methods:
var sample = db.Database
.OrderByDescending(x => x.RecordId)
.Select(y => y.RecordId)
.FirstOrDefault();
(They happen to be extension methods here, but of course they don't have to be...)
You use lambda expressions to express how you want the ordering and projection to be performed, and the compiler converts those into expression trees (assuming this is EF or similar; it would be delegates for LINQ to Objects).
The second example is a query expression, although it doesn't actually match your first example. A query expression corresponding to your original query would be:
var sample = (from x in db.Database
orderby x.RecordId descending
select x.RecordId)
.FirstOrDefault();
Query expressions are very much syntactic sugar. The compiler effectively converts them into the first form, then compiles that. The range variable declared in the from clause (x in this case) is used as the parameter name for the lambda expression, so select x.RecordId becomes .Select(x => x.RecordId).
Things become a bit more complicated with joins and multiple from clauses, as then the compiler introduces transparent identifiers to allow you to work with all the range variables that are in scope, even though you've really only got a single parameter. For example, if you had:
var query = from person in people
from job in person.Jobs
order by person.Name
select new { Person = person, Job = job };
that would be translated into the equivalent of
var query = people.SelectMany(person => person.Jobs, (person, job) => new { person, job } )
.OrderBy(t => t.person.Name)
.Select(t => new { Person = t.person, Job = t.job });
Note how the compiler introduces an anonymous type to combine the person and job range variables into a single object, which is used later on.
Basically, query expression syntax makes LINQ easier to work with - but it's just a translation into other C# code, and is neatly wrapped up in a single section of the C# specification. (Section 7.16.2 of the C# 5 spec.)
See my Edulinq blog post on query expressions for more detail on the precise translation from query expressions to "regular" C#.

Related

Entity Framework Core GroupBy Date

In C# you can group by .Date:
db.History.GroupBy(x => x.Timestamp.Date)
.Select(g => new { key = g.Key, aggregate = g.Count() })
However, the equivalent F# does not work:
db.History.GroupBy(fun x -> x.Timestamp.Date)
.Select(fun g -> { Date = g.Key; Count = g.Count()} )
The relevant record:
type DateCount = {
Date: DateTime
Count: int
}
It throws the following error:
System.InvalidOperationException: The LINQ expression 'DbSet<HistoryEntity>
.GroupBy(
source: h => copyOfStruct => copyOfStruct.Date.Invoke(h.Timestamp),
keySelector: h => h)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
How can I group by date?
So in C#, when you use LINQ-to-SQL queries, you are using the extension methods on IQueryable<T>. If we look at the signature of say, the GroupBy method, you will see that the function signature is actually
IQueryable<TSource>.GroupBy<TSource,TKey>(Expression<Func<TSource,TKey>> keySelector)
What's going on? Expression<> is a special type - when the C# compiler spots an Expression<> type, the compiler builds an AST, and passes the AST object (of type Expression<Func<>>), instead of the usual delegate. The underlying functions are expected to inspect the AST and build whatever query expression is finally needed, like SQL for querying the database.
You can try it yourself:
Expression<Func<int>> getRandom = () => 4; //random, chosen by fair dice roll
You can inspect the properties of getRandom to see the AST.
Since the magic happens in the C# compiler, when you do it in F#, this won't cut it.
To go into more detail, the F# compiler can recognize the Expression<>, but it does so by applying an implicit F# quotation - so you get an F# quotation wrapped method call that translates to the C# expression tree. (Sorry if, that was run on.)
F# has its own query comprehension builder for SQL. It lets you write the computation expressions like that of seq which translate to SQL queries. This works like you'd expect.
query {
for record in db do
select record
}
Group by .Date works when using in a query expression.
query {
for h in db.History do
groupValBy h h.Timestamp.Date into g
select {
Date = g.Key
Count = g.Count()
}
}
Code stolen from here.
If someone could explain why the query expression works but the LINQ version doesn't, I'd appreciate it :)

Can you convert this Linq statement into Lambda without using join statements?

I see this all over the web, however I'm curious if there isn't an easier way to write this in lambda?
var x = from c in db.Client
from p in db.Prospects
from ct in db.Countys
select new ViewModelExcelReport
{
client = c.ClientName,
cntyCounty = ct.County,
sctSection = p.Section
};
I would like to see a lambda expression that does NOT use joins, as though i am almost certain that i have seen one without the joins, but if this isn't possible ofcouse i'd like to see one with, thanks.
Basically multiple from clauses contribute SelectMany calls. So your code is something like:
var x = db.Client
.SelectMany(c => db.Prospects, (c, p) => new { c, p })
.SelectMany(z => db.Countys, (z, ct) => new { z, ct })
.Select(zz => new ViewModelExcelReport
{
client = zz.z.c.ClientName,
cntyCounty = zz.ct.County,
sctSection = zz.z.p.Section
});
Note how this is rather more longwinded than the query expression - the compiler takes care of keeping track of all the range variables via transparent identifiers. Why do you want this in lambda form? What do you see as being the benefit? The query expression will be translated into exactly the same code, so you should use whichever one is clearer - which in this case looks like the query expression, IMO.
As an aside, I'd strongly recommend that you change your property names (in ViewModelExcelReport) to more idiomatic ones if you possibly can.

Linq to Entities Query explanation

Is there any way I can make this Linq to entities query in another way (better) and understand what I did?
First, can I have the string.jon() in the first part (select(p => new {...)?
Second, why do I need the first select to end with .ToList() for the string.join() to work?
The tables relation are as follow:
And here is the code:
Productos.Select(p => new {
Id = p.Id,
Code = p.CodigoProd,
Name = p.Nombre,
Cant = p.Inventario.Sum(i => i.Cantidad),
Pric = p.Inventario.OrderBy(i => i.Precio).Select (i => i.Precio).FirstOrDefault(),
cate = p.ProductosXCategoria.Select(pc => pc.CategoriasdeProducto.Nombre)
}).Where (p => p.Cant != null).ToList()
.Select (r => new {
r.Id, r.Code, r.Cant, r.Name, r.Pric, Categ = string.Join("-",r.cate)
})
the result is this (which is the result i expected to be):
IEnumerable<> (17 items)
**Id-- Code-- Cant-- Name-- Pric-- Categ**
1-- AXI-- 30-- Pepsi-- 10-- Granos
3-- ASI-- 38-- Carne blanca-- 12-- Granos-Limpieza
The query looks fine to me.
The reason you can't move the string.Join method to the first Select, is that LINQ-to-Entities ultimately has to be able to translate to SQL. string.Join has no direct translation to SQL, so it doesn't know how to translate your LINQ query to it. By calling ToList() first, you bring the results of the first Select into memory, where the subsequent Select works with Linq-to-Objects. Since Linq-to-Objects does not need to translate to SQL, it can operate directly on the results of the first query in memory.
Generally, you would want to put everything that would be better left to SQL before the ToList() call (such as filtering, sorting, averaging, grouping, etc.), and leave additional work that can't be translated to SQL (or isn't as efficient to do so) for after the results have been brought into local memory.

Var vs IEnumerable when it comes to Entity Framework

If I were to use IEnumerable instead of var in the code example below, will the SQL be generated only during the execution of the foreach statement? Or will it execute as an when the Linq statements are evaluated?
var query = db.Customers.Where (c => c.Age > 18);
query = query.Where (c => c.State == "CO");
var result = query.Select (c => c.Name);
foreach (string name in result) // Only now is the query executed!
Console.WriteLine (name);
Another example:
IEnumerable<Order> query = db.Orders.Where(o => o.Amount > 1000);
int orderCount = query.Count();
Would it be better to use var (or IQueryable) as it would be executed a select count(*)... when .Count() is executed or would it be exactly same with the IEnumerable code shown above?
It would make no difference. var is just syntactic sugar. If you hover over var, you will see what type C# thinks your query is.
From http://msdn.microsoft.com/en-us/library/bb383973.aspx
Beginning in Visual C# 3.0, variables that are declared at method scope can have an implicit type var. An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type. The following two declarations of i are functionally equivalent:
var i = 10; // implicitly typed
int i = 10; //explicitly typed
If you want to perform actions on your query that SQL wouldn't know what to do with, such as a method defined in your class, then you could use AsEnumerable().
For example:
var query = db.Customers
.Where(c => c.Age > 18)
.AsEnumerable()
.Select(c => GetCustomerViewModel());
//put definition of GetCustomerViewModel() somewhere in the same class
Update
As Omar mentioned, if you want your query to be executed immediately (rather than deferred), use ToList(). This will immediately enumerate the IQueryable/IEnumerable and fill the list with the actual data from the database.
In general, the SQL is generated when GetEnumerator is called on the IQueryable.
In your example, there is a subtle difference that you may want to consider. Let's take your original example:
var query = db.Customers.Where (c => c.Age > 18);
query = query.Where (c => c.State == "CO");
var result = query.Select (c => c.Name);
In this case if you change your first query to IEnumerable query = ..., then the second line would use the IEnumerable version of the Where extension (LINQ to Objects) rather than the IQueryable one (LINQ to SQL/EF). As a result, when we start iterating, the first where clause is passed to the database, but the second where clause is performed on the client side (because it has already been converted to an IEnumerable).
Another subtle item you want to be aware of is the following type of code:
var query = db.OrderBy(c => c.State);
query = query.Customers.Where(c => c.Age > 18); // Fails: Widening
In this case, since your original query returns IOrderedQueryable rather than IQueryable. If you try to then assign query to the result of the .Where operation, you're trying to widen the scope of the return type and the compiler will refuse to perform that widening. As a result, you have to explicitly specify the baseline type rather than using var:
IQueryable<Customer> query = db.OrderBy(c => c.State); // Is narrowing rather than widening.
query = query.Customers.Where(c => c.Age > 18);
Linq queries return IQueryable<> or IEnumerable<>, the execution of both is deferred.
As DanM stated, whether or not you use var or IEnumerable<> it all depends on the return value of the method you're calling: if it's an IEnumerable<> or IQuerable<> it'll be deferred, if you use .ToList(), it'll be executed right away.
When to use var comes down to personal choice/style. I generally use var when the return value is understood from the line of code and variable name or if I'm instantiating a generic with a long declartion, e.g. Dictionary<string, Func<Order, object>>.
From your code, it's clear that a collection of Customers/Orders is returned, so I would use the var keyword. Again, this is a matter of personal preference.

Linq: Dynamic Query Contruction: query moves to client-side

I've been following with great interest the converstaion here:
Construct Query with Linq rather than SQL strings
with regards to constructing expression trees where even the table name is dynamic.
Toward that end, I've created a Extension method, addWhere, that looks like:
static public IQueryable<TResult> addWhere<TResult>(this IQueryable<TResult> query, string columnName, string value)
{
var providerType = query.Provider.GetType();
// Find the specific type parameter (the T in IQueryable<T>)
var iqueryableT = providerType.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), null).FirstOrDefault();
var tableType = iqueryableT.GetGenericArguments()[0];
var tableName = tableType.Name;
var tableParam = Expression.Parameter(tableType, tableName);
var columnExpression = Expression.Equal(
Expression.Property(tableParam, columnName),
Expression.Constant(value));
var predicate = Expression.Lambda(columnExpression, tableParam);
var function = (Func<TResult, Boolean>)predicate.Compile();
var whereRes = query.Where(function);
var newquery = whereRes.AsQueryable();
return newquery;
}
[thanks to Timwi for the basis of that code]
Which functionally, works.
I can call:
query = query.addWhere("CurUnitType", "ML 15521.1");
and it's functionally equivalent to :
query = query.Where(l => l.CurUnitType.Equals("ML 15521.1"));
ie, the rows returned are the same.
However, I started watching the sql log, and I noticed with the line:
query = query.Where(l => l.CurUnitType.Equals("ML 15521.1"));
The Query generated is:
SELECT (A bunch of columns)
FROM [dbo].[ObjCurLocView] AS [t0]
WHERE [t0].[CurUnitType] = #p0
whereas when I use the line
query = query.addWhere("CurUnitType", "ML 15521.1");
The query generated is :
SELECT (the same bunch of columns)
FROM [dbo].[ObjCurLocView] AS [t0]
So, the comparison is now happening on the client side, instead of being added to the sql.
Obviously, this isn't so hot.
To be honest, I mostly cut-and-pasted the addWhere code from Timwi's (slightly different) example, so some of it is over my head. I'm wondering if there's any adjustment I can make to this code, so the expression is converted into the SQL statement, instead of being determined client-side
Thanks for taking the time to read through this, I welcome any comments, solutions, links, etc, that could help me with this. And of course if I find the solution through other means, I'll post the answer here.
Cheers.
The big problem is that you're converting the expression tree into a delegate. Look at the signature of Queryable.Where - it's expressed in expression trees, not delegates. So you're actually calling Enumerable.Where instead. That's why you need to call AsQueryable afterwards - but that doesn't do enough magic here. It doesn't really put it back into "just expression trees internally" land, because you've still got the delegate in there. It's now wrapped in an expression tree, but you've lost the details of what's going on inside.
I suspect what you want is this:
var predicate = Expression.Lambda<Func<TResult, Boolean>>
(columnExpression, tableParam);
return query.Where(predicate);
I readily admit that I haven't read the rest of your code, so there may be other things going on... but that's the core bit. You want a strongly typed expression tree (hence the call to the generic form of Expression.Lambda) which you can then pass into Queryable.Where. Give it a shot :)

Resources