Get Expression Tree for LINQ IQueryable - linq

I'm trying to implement my own Remote LINQ execution for EF Core. So, as usual the problem is connected with serialization.
Let's imagine that I have an IQueryable<T> object and its Expression, something like this:
var sameTestData = new List<int>() { 1, 2, 3 };
var queryableExpresssion = myTestDbContext.Users.Include(e => e.SameTable1)
.Include(f => f.SameTable2)
.Where(s => sameTestData.Contains(s.Id))
.Select(t => t.FullName)
.Expression;
So, I have 2 questions:
1) The main problem is an MethodCallExpression identification problem: how to check whole tree and divide Expression derived types into 2 collections - with LambdaExpression type an other types.
2) Are there any libraries which perform Expression Tree parsing?
Thank you.

Related

how to get the linq list having Ids from IEnumerable<Object>

The code below userModel.Carriers is the type of IEnumerable<CarrierModel>.
userModel.Carriers has a list of carriers having Ids. With those Ids, I want to get CarrierDivision usign linq. But, I can't get it right because linq sqlexpression is not compatible with IEnumerable expression.
userModel.Carriers = carriersForRegion.Select(carrier => Mapper.Map<CarrierModel>(carrier))
.ToList();
var carrierDivision = from c in db.CarrierDivision where c.Contains();
collection.Contains will generate .. WHERE CarrierId IN (1, 2, 3) sql query
var carrierIds = userModel.Carriers.Select(carrier => carrier.Id).ToArray();
var divisions = db.CarrierDivision
.Where(division => carrierIds.Contains(division.CarrierId))
.ToArray();
In case db.CarrierDivision returns IEnumerable(not database), then I would suggest to create HashSet of carrier ids.
var carrierIds = userModel.Carriers.Select(carrier => carrier.Id).ToHashSet();
var divisions = db.CarrierDivision
.Where(division => carrierIds.Contains(division.CarrierId))
.ToArray();
With HashSet search executed without extra enumerations - O(1)

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

Can this Aggregate Lambda expression be converted to a LINQ query?

I have a list of integers summed by an Aggregate method using a Lambda expression:
var mylist = new int[] { 3, 4, 5 };
var result = mylist.Aggregate((a, b) => a + b);
As I understand it, a Lambda expression can always be converted to a LINQ query. How would such a LINQ query look for my example?
EDIT: I understand .Sum may be better to add the numbers in my example. But I would really like to know how this Aggregate will look with a LINQ Query instead.
It already IS a LINQ query, Aggregate is a LINQ operator, i'm assuming what you meant was how it would look like in the LINQ comprehension syntax? The comprehension syntax only has a few built in features (select , where, multiple selects, groupby etc), it doesn't have all operators built in so when you need one of those (such as aggregate) you wrap it around parenthèses and keep going with the regular syntax. Since there is nothing there except aggregate it's not possible to give an example so i'll go from a different query:
var mylist = new int[] { 3, 4, 5, 6, 7, 8 };
var result = mylist
.Where(item=>item %2 == 0)
.Aggregate((a, b) => a + b);
var ComprehensiveResult =
(from item in mylist
where item % 2 == 0
select item)
.Aggregate((a, b) => a + b);
Comprehensive syntax is more of a "LINQ for people coming from SQL introduction", there's nothing you can do in it that you can't do with plain using the operators but the reverse isn't true as not all operators have built in replacements. The only thing that comes to mind where Comprehensive syntax is better (aside from personal taste) is multiple selects to generate a cartesian product which is much harder to maintain in plain method syntax.
In this case Aggregate function adds numbers each other. So, the equivalent function is SUM:
var qry = mylist.Sum(x=>x);
or
var qry = (from n in mylist select n).Sum();
[EDIT]
OP has added extra information to the question without informing me about that.
Yes, it's possible to "convert" Aggregate function into linq query, but extension method is needed. See this article: Cumulating values with LINQ

Linq in conjunction with custom generic extension method build error - An expression tree may not contain an assignment operator?

I've made a generic extension method that executes an action on an object and returns the object after that:
public static T Apply<T>(this T subject, Action<T> action)
{
action(subject);
return subject;
}
I'm unable to use this extension method in an EntityFramework Linq query because of:
An expression tree may not contain an assignment operator
Why is this?
The Linq query:
var parents = from p in context.Parent
join phr in context.Child on p.key equals phr.parentkey
into pr
select p.Apply(
x => x.Children = //The assignment operator that fails to build...
pr.ToDictionary(y => y.childkey, y => y.childname));
Well, assignment operator aside, how would you expect your Apply method to be translated into SQL? Entity Framework doesn't know anything about it, and can't delve into opaque delegates, either.
I suspect what you really need to do is separate out the bits to do in the database from the bits to do locally:
var dbQuery = from p in context.Parent
join phr in context.Child on p.key equals phr.parentkey into pr
select new { p, phr };
var localQuery = dbQuery.AsEnumerable()
.Select(pair => /* whatever */);

C# HashSet union on IEnumerable within LINQ Func expression does not work (possible precompiler bug)

I am using using Microsoft .NET Framework 4.0.
I have run into this using Aggregate on a Dictionary<T, List<T>> to extract the set of type T values used across all type List<T> lists in the dictionary. Here is the simplest case I could come up with that exhibits the same behaviour.
First, as the documentation states, the following does work:
var set = new HashSet<int>();
var list = new LinkedList<int>();
var newSet = set.Union(list);
That is, I can call Union on a HashSet with a List as the argument (since it implements IEnumerable).
Whereas, the equivalent expression within a Func argument of the LINQ Aggregate expression produces an error (precompiler at least):
new List<int>[] { new List<int>() }.Aggregate(new HashSet<int>(), (acc, list) => acc.Union(list));
It expects the argument of Union to be HashSet, and will cooperate if it is given one, contrary to its behaviour outside LINQ/Func expressions.
The real world example I was using when I came across the problem was:
public AdjacencyListGraph(Dictionary<TVertex, LinkedList<TVertex>> adjacencyList)
{
var vertices = adjacencyList.Aggregate(new HashSet<TVertex>(),
(vertices, list) => vertices.Union(list.Value));
}
Which complains that it cannot convert IEnumerable<TVertex> to HashSet<TVertex>...
The problem here is in your understanding of the Select method. The lambda passed in does not recieve the list but instead elements of the list. So the variable you've named list is in fact of type int which is not compatible with Union.
Here is a more explicit example of what you're trying to do
new List<int>().Select( (int list) => new HashSet<int>().Union(list));
With the type infererence removed it's much clearer why this doesn't work.
The problem actually lies in trying to replace the accumulator type of HashSet with the IEnumerable, .Union method doesn't add items to HashSet, but returns the new IEnumerable on the resulting union.
You should change your code to the following:
// select from keys
var vertices = new HashSet<TVertex>(adjacencyList.Keys);
or
// select from values
var vertices = new HashSet<TVertex>(adjacencyList.SelectMany(dictEntry => dictEntry.Value));
new List<int>().Select(list => new HashSet<int>().Union(list));
I think you would expect to use SelectMany here, unless you want the result to be IEnumerable<IEnumerable<T>>.

Resources