Nested "From" Linq Query Expressed with Extension Methods

Nested from LINQ query expressed with extension methods

For your future reference, all questions of this form are answered by section 7.16 of the C# specification.

Your specific question is answered by this paragraph:


A query expression with a second from clause followed by a select clause

from x1 in e1
from x2 in e2
select v

is translated into

( e1 ) . SelectMany( x1 => e2 , ( x1 , x2 ) => v )

So your query:

var query = from a in sequenceA            
from b in sequenceB
select ...;

Is the same as

var query =  ( sequenceA ) . SelectMany( a => sequenceB , ( a , b ) => ... )

(Note that of course this assumes that the "..." is an expression, and not, say, an expression followed by a query continuation.)

hdv's answer points out that

var query =  ( sequenceA ) . SelectMany( 
a => ( sequenceB ) . Select( b => ... ) );

would also be a logically valid translation, though it is not the translation we actually perform. In the early days of LINQ implementation, this was the translation we chose. However, as you pile on more from clauses, it makes the lambdas nest more and more deeply, which then presents the compiler with an enormous problem in type inference. This choice of translation wrecks compiler performance, so we introduced the transparent identifier mechanism to give us a much cheaper way to represent the seamntics of deeply nested scopes.

If these subjects interest you:

For more thoughts on why deeply nested lambdas present a hard problem for the compiler to solve, see:

http://blogs.msdn.com/b/ericlippert/archive/2007/03/26/lambda-expressions-vs-anonymous-methods-part-four.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/03/28/lambda-expressions-vs-anonymous-methods-part-five.aspx

For more information about transparent identifiers, see this post from Wes Dyer, who implemented them in C# 3.0:

http://blogs.msdn.com/b/wesdyer/archive/2006/12/22/transparent-identifiers.aspx

And my series of articles about them:

http://ericlippert.com/2014/07/31/transparent-identifiers-part-one/

Convert linq query expression with multiple froms into extension method syntax

var query = _context.Customer
.Where(c => c.Orders.Any(o => o.DateSent == null))
.Select(c => new CustomerSummary
{
Id = c.Id,
Username = c.Username,
OutstandingOrderCount = c.Orders.Count(o => o.DateSent == null)
};

Creating Extension method to include subquery

I found an other way of returning the same result using a Generic Way.

    public static IQueryable IncludeTranslation<S>(this IQueryable<S> source, Expression<Func<S, string>> keyField)
where S : class
{
IQueryable<CFG_TRANSLATION> translations = GetTranslations();
var trans = source.GroupJoin(translations, keyField, t => t.TR_TEXT, (s, t) => new { Source = s, Translations = t });
var result = trans.Select(t => new {
Source = t.Source,
Translation = t.Translations
.FirstOrDefault()
});
return result;
}

Maybe someone can use this as a sollution

this can be called as follow

var Result = QueryableTable.IncludeTranslation(t => t.FieldToTranslate);

LINQ-to-SQL and Extension method in subQuery

When i use my extension method in a simple query, it's working, but when i use it in a sub query it's not working. Any solutions ?

Working

var test = from pl in t.ProductLocales.FilterCultureSubQuery()  select pl;

Not Working

var test = from p in t.Products
select new
{
Allo = p,
Allo2 = (from pl in t.ProductLocales.FilterCultureSubQuery()
select pl)
};

I create a new extension method and rewrite the expression tree of the query.

var test = (from p in t.Products
select new
{
Allo = p,
Allo2 = (from pl in t.ProductLocales.FilterCultureSubQuery()
select pl)
}).ArrangeExpression();

LINQ-TO-SQL have difficulty to use extension method in subquery. With a rewrite expression extension method everyting working fine.

Any other solutions ?

How to convert Linq-to-objects query with two from clauses to method syntax

Two consecutive from-clauses are translated with a SelectMany extension method:

var occupiedSquares = squares
.SelectMany(s => pieces.Select(p => (s, p))) // Creates a ValueTuple
.Where(x => Occupies(x.p, x.s))
.Select(x => x.s);

If you are working with an older Framework version, you can also use an Anonymous Type instead of a ValueTuple.

var occupiedSquares = squares
.SelectMany(s => pieces.Select(p => new { s, p }))
.Where(x => Occupies(x.p, x.s))
.Select(x => x.s);

Alternatively, you can also apply the Where-clause to the nested Select. No aggregate (ValueTuple or anonymous type) is required in this case:

var occupiedSquares = squares
.SelectMany(
s => pieces
.Where(p => Occupies(p, s))
.Select(p => s)
);

The Enumerable.SelectMany Method is typically used to flatten a nested collection. E.g., you have a list of users and the user objects have a list of posts and you need a list of all the posts.

See also my question Nested “from” LINQ query expressed with extension methods and Eric Lippert's answer. (Eric was part of Microsoft's C# compiler team.)

LinqKit applying nested filtering through extension-method not working

You have to mark your Get method as expandable:

[Expandable(name(GetEnumerable))]
public static IEnumerable<TEntity> Get<TEntity, TEntityFilter>(this IEnumerable<TEntity> entities, TEntityFilter filter)
where TEntity : BaseEntity<TEntity>, new()
where TEntityFilter : EntityFilter<TEntity>
{
return entities.Where(e => filter.FilterExpression.Expand().Invoke(e));
}

private static Expression<Func<IEnumerable<TEntity>, TEntityFilter, IEnumerable<TEntity>>> GetEnumerablet<TEntity, TEntityFilter>()
{
return (entities, filter) =>
entities.Where(e => filter.FilterExpression.Expand().Invoke(e));
}

Multiple from clauses in LINQ

Enumerable.Range(1, 3).SelectMany(
i => Enumerable.Range(4, 3),
(i, j) => new Tuple<int, int>(i, j)
).ToList();

Multiple WHERE Clauses with LINQ extension methods

Two ways:

results = results.Where(o => (o.OrderStatus == OrderStatus.Open) &&
(o.CustomerID == customerID));

or:

results = results.Where(o => (o.OrderStatus == OrderStatus.Open))
.Where(o => (o.CustomerID == customerID));

I usually prefer the latter. But it's worth profiling the SQL server to check the query execution and see which one performs better for your data (if there's any difference at all).

A note about chaining the .Where() methods: You can chain together all the LINQ methods you want. Methods like .Where() don't actually execute against the database (yet). They defer execution until the actual results are calculated (such as with a .Count() or a .ToList()). So, as you chain together multiple methods (more calls to .Where(), maybe an .OrderBy() or something to that effect, etc.) they build up what's called an expression tree. This entire tree is what gets executed against the data source when the time comes to evaluate it.



Related Topics



Leave a reply



Submit