Linq to Entities Query explanation - linq

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.

Related

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

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

Nested query using Linq with ToDictionary

I'm having problems with this query using entity framework 4:
List<SomeResult> test = (from a in _entities.TableA
select new SomeResult
{
TestB = a.TableB.Name,
TestCDict = a.TableC.ToDictionary(x => x.SomeKey, x => x.SomeValue)
}).ToList();
It gives this error:
"Cannot compare elements of type 'System.Data.Objects.DataClasses.EntityCollection`1'. Only primitive types (such as Int32, String, and Guid) and entity types are supported."
How can I redo this query so it'll work? from a in _entities.TableA from c in a.TableC ....ToDictionary(.. ?
/Lasse
The problem is, that you are doing query against database. And LINQ provider that you are using, actually don't execute any of the operations, that you have written. It only tryes to translate all your code in Select into database query. Obviously, it can't parse really complex statents, like you have written with ToDictionary().
You can simply load all data from entities into memory, and then do all your dictionary stuff. Then your code will actually be executed, and should work.
Like:
List<SomeResult> test = from a in (from aa in _entities.TableA).AsEnumerable())
select new SomeResult
{
TestB = a.TableB.Name,
TestCDict = a.TableC.ToDictionary(x => x.SomeKey, x => x.SomeValue)
}).ToList();
Of course you can use DB side filtering in the inner query (before AsEnumerable()) to narrow amount of data loaded into memory.

Nhibernate linq. The where extension method does not add the where clause to the SQL command, why?

I want to add the where clause to a linq statement, but it doesn't behave as i would expected it to.
When i use this code:
IQueryable<Employee> EmpQuery = from e in Session.Query<Employee>() where e.Surname == "Test" select e;
EmpQuery.ToList();
or i use this code:
IQueryable<Employee> EmpQuery = (from e in Session.Query<Employee>() select e).Where(e => e.Surname == "Test");
EmpQuery.ToList();
The where clause is included in the SQL command, but when i try it this way:
IQueryable<Employee> EmpQuery = from e in Session.Query<Employee>() select e;
EmpQuery.Where(e => e.Surname == "Test");
The where clause is not included in the SQL command. Why is this? Is there another way to dynamically add criteria to a Nhibernate Linq query?
You're not using the return value of Where. LINQ is designed around functional concepts - calling Where doesn't modify the existing query, it returns a new query which applies the filter. The existing query remains as it was - which means you can reuse it for (say) a different filter.
Note that your current query expression (from x in y select x, effectively) is pretty pointless. I would suggest simply writing:
var query = Session.Query<Employee>().Where(e => e.Surname == "Test");
Just to clarify on Jon's remark, your implementation would be fine with the following tweak:
IQueryable<Employee> modifiedQuery = EmpQuery.Where(e => e.Surname == "Test");
Then just invoke the appropriate enumerator (ToList, ToArray, foreach) on modifiedQuery. And I wouldn't say that it create a complete new query, but instead creates a query which wraps around the original (kind of along the lines of the adapter pattern). Granted, your example doesn't need the additions, but this is how you would add additional criteria onto an existing LINQ expression, and that is what your question actually asked.

Differences between LINQ to Objects and LINQ to SQL queries

I have been using LINQ to query my POCO objects for some time, but I have not yet tried LINQ to SQL. I assume that LINQ to SQL queries are somehow converted to equivalent SQL queries and, given this, I am wondering if that affects the way LINQ to SQL queries are or should be written.
Are there any significant differences between LINQ to Objects and LINQ to SQL that affect how I should write a query for either?
The main difference is as you say, LINQ to SQL queries are converted into SQL. That means that there is code you can write which isn't actually convertible or has some subtly different semantics - and you only find that out at execution time.
For example:
var query = from person in people
where person.Age == person.GetHashCode()
select person;
will compile fine, but fail at execution time because LINQ to SQL doesn't know what to do with GetHashCode().
Basically I find LINQ to SQL a lot harder to predict than LINQ to Objects. That's not to say it's not useful - it's just a slightly different world. MS has done an amazing job at letting you write queries which very often just do what you expect them to, but it can't do everything.
LINQ to SQL will use the column DB server's collation for Where and OrderBy. LINQ to Objects will use string comparisons. So the former might be case-insensitive while the latter is case-sensitive. LINQ to Entities coalesces nulls. I presume L2S does the same, but I haven't tested. So in L2E you can do:
let foo = item.Property.SomeNullableType
... and foo will be null if Property is null. But in LINQ to Objects you'd have to do something like:
let foo = item.Property != null ? item.Property.SomeNullableType : null
... or you'd get a null exception.
MSDN reference here and here should help you out.
One difference that I run into is differences in grouping.
When you group in linq to objects, you get a hierarchically shaped result (keys, with child objects).
When you group in SQL, you get keys and aggregates only.
When you group in linq to sql, if you ask for the child objects (more than aggregates), linq to sql will re-query each group using the key to get those child objects. If you have thousands of groups, that can be thousands of roundtrips.
//this is ok
var results = db.Orders
.GroupBy( o => o.CustomerID )
.Select(g => new
{
CustomerId = g.Key,
OrderCount = g.Count()
});
//this could be a lot of round trips.
var results = db.Orders
.GroupBy( o => o.CustomerID )
.Select(g => new
{
CustomerId = g.Key,
OrderIds = g.Select(o => o.OrderId)
});
// this is ok
// used ToList to separate linqtosql work from linqtoObject work
var results = db.Orders
.Select(o => new {o.CustomerId, o.OrderId})
.ToList()
.GroupBy(o => o.CustomerId)
.Select(g => new
{
CustomerId = g.Key,
OrderIds = g.Select(o => o.OrderId)
});

Does Enumerable.ToDictionary only retrieve what it needs?

I'm using Enumerable.ToDictionary to create a Dictionary off of a linq call:
return (from term in dataContext.Terms
where term.Name.StartsWith(text)
select term).ToDictionary(t => t.TermID, t => t.Name);
Will that call fetch the entirety of each term, or will it only retrieve the TermID and the Name fields from my data provider? In other words, would I be saving myself database traffic if I instead wrote it like this:
return (from term in dataContext.Terms
where term.Name.StartsWith(text)
select new { term.TermID, term.Name }).ToDictionary(t => t.TermID, t => t.Name);
Enumerable.ToDictionary works on IEnumerable objects. The first part of your statement "(from ... select term") is an IQueryable object. Queryable is going to look at the expression and build the SQL statement. It will then convert that to an IEnumerable to pass to ToDictionary().
In other words, yes, your second version would be more efficient.
The generated SQL will return the entire term, so your second statement will bring down just what you need.
You can set dataContext.Log = Console.Out and look at the different results of the query.
Using my sample LINQPad database, here's an example:
var dc = (TypedDataContext)this;
// 1st approach
var query = Orders.Select(o => o);
dc.GetCommand(query).CommandText.Dump();
query.ToDictionary(o => o.OrderID, o => o.OrderDate).Dump();
// 2nd approach
var query2 = Orders.Select(o => new { o.OrderID, o.OrderDate});
dc.GetCommand(query2).CommandText.Dump();
query2.ToDictionary(o => o.OrderID, o => o.OrderDate).Dump();
The generated SQL is (or just peek at LINQPad's SQL tab):
// 1st approach
SELECT [t0].[OrderID], [t0].[OrderDate], [t0].[ShipCountry]
FROM [Orders] AS [t0]
// 2nd approach
SELECT [t0].[OrderID], [t0].[OrderDate]
FROM [Orders] AS [t0]
No. ToDictionary is an extension method for IEnumerable<T> not IQueryable<T>. It doesn't take an Expression<Func<T, TKey>> but simply a Func<T, TKey> that it'll blindly call for each item. It doesn't care (and doesn't know) about LINQ and the underlying expression trees and stuff like that. It just iterates the sequence and builds up a dictionary. As a consequence, in your first query, all columns are fetched.

Resources