Entity Framework query builder methods: why "it" and not lambdas? - c#

I'm just getting started with EF and a query like the following strikes me as odd:
var departmentQuery =
schoolContext.Departments.Include("Courses").
OrderBy("it.Name");
Specifically, what sticks out to me is "it.Name." When I was tooling around with LINQ to SQL, pretty much every filter in a query-builder query could be specified with a lambda, like, in this case, d => d.Name.
I see that there are overrides of OrderBy that take lambdas that return an IOrderedQueryable or an IOrderedEnumable, but those obviously don't have the Execute method needed to get the ObjectResult that can then be databound.
It seems strange to me after all I've read about how lambdas make so much sense for this kind of stuff, and how they are translated into expression trees and then to a target language - why do I need to use "it.Name"?

I get lamdba expressions with mine; I can do Where (it.SomeProperty == 1)... do you have System.Linq as a namespace? You can try restructuring as:
var departmentQuery = from d in schoolContext.Departments.Include("Courses")
orderby d.Name
select d;
Those are some possibilities.
HTH.

Related

What are the ways to create the LINQ query expression using query syntax dynamically?

What are the possible ways to create a LINQ expression dynamically, but using the query syntax? Is the query syntax a C# thing only, and if so, is the only viable way of creating such expressions using Roslyn dynamic compilation?
When writing LINQ expressions manually, I find them more natural when written using method chaining syntax, for example ctx.Foo.Where(foo => foo.Type.Name == "Bar") but there are some cases where I would need to write them like this:
from foo in ctx.Foo
join fooType in ctx.Types on foo.TypeId equals fooType.Id
where fooType.Name == "Bar"
I love how expression trees ensure type safety when creating expressions dynamically, but how would one create expressions using the query syntax?
Thanks everyone for your comments.
So it turns out it's not possible to do this because query syntax is just a C# language syntactic sugar.
Additionally, if someone else stumbles upon this question, take a look at the excellent answer by #Gert: https://stackoverflow.com/a/15599143/828023
That answer explains that the query syntax is "sugar", while the method syntax shows what really goes on under the hood, where for example join x in y on z equals x.something into somethingElse is actually a GroupJoin method call and there is no way to express this with expression trees without actually calling GroupJoin.

Can a method chain be called LINQ?

Is it correct to call this code snippet LINQ (Language Integrated Query)?
var lstMyStrings = new List<string>();
lstMyStrings.Where(aX => string.IsNullOrEmpty(aX))
.Skip(3)
.ToList();
I am confused because System.Linq is mandatory for this code.
However, when I see questions and answer's like this: .NET LINQ query syntax vs method chain
, then they're talking explicit about a method chain and not LINQ.
LINQ can be written in two different ways.
One is by writing a query using LINQ declarative query syntax:
var query = from x in source
where condition
select x.Property
And the other is by using LINQ's extension methods:
var query = source.Where(condition).Select(x => x.Property);
Both queries are identical and will produce the same result (well, compiler error in this over-simplified example but it's the thought that counts :-))
The c# compiler translates the query into method calls.
This means that everything you write as a query can be also written using method chains. Please note, however, that the opposite is false - Some queries can only be written using Linq's extension methods.
For further reading, here's what Microsoft have to say about it.
Note the second paragraph starts with this:
Query syntax and method syntax are semantically identical, but many people find query syntax simpler and easier to read.
btw, if it was'nt already clear, the reason that System.Linq is mandatory for the method chaining syntax also is because the linq extension methods belongs to this namespace.

What am I using? (Linq/sql) [duplicate]

This question already has answers here:
Linq query or Lambda expression?
(5 answers)
Closed 7 years ago.
My project currently uses for following syntax for "linq"
var le = domainModel.EntityDataContext.Table_name_here.Query()
.WithFullReadCheck(domainModel.Security)
.Where(x => x.Metadata.AdvisorID == advisorId).FirstOrDefault();
It is said the above code is linq, being unaware about linq I decided to learn it. However, on https://msdn.microsoft.com/en-us/library/gg509017.aspx , things are pretty different.
what is being used in my code? Is it a version of linq? Is it something else?
What you are using is LINQ. There are 2 different notations you can use for writing LINQ - Lambda Syntax and Query Syntax
The difference is explained here: LINQ: Dot Notation vs Query Expression
There is more information on this on MSDN here: https://msdn.microsoft.com/en-us/library/bb308959.aspx
The MSDN articles starts explaining LINQ with SQL-like syntax ("query syntax") and then goes on to explain Lambda Expressions and Expression Trees ("lamba syntax").
That is extension method syntax for a query. The .Query().WithFullReadCheck() are much less common, but the rest .Where and .FirstOrDefault are pretty common query extensions. LINQ is a special syntax for expressing the same thing that can be done with chaining the query extension methods. Behind the scenes, they are identical.
See this question which gives an example of both LINQ and extension method syntax and has a good discussion of the differences between them: Extension methods syntax vs query syntax
Linq (language integrated query) is the language you use to query the data. You don't care where do they come from, that's the whole point of using it. You can use the same code to query arrays, collections, databases, xml files, directories, whatever... Linq translates your code in the background, so if you use it for instance to get the data from a database, it produces SQL to be sent to the database.
There are two syntax versions available:
1.) lambda syntax
2.) chainable methods
It doesn't matter which one you chose, just try to be consistent with it and use what makes you more comfortable / makes more sense in your situation.
LINQ is 'Language INtegrated Query'. In practical terms it means two things to most people:
The way that inline delegates are converted by the compiler into expression trees, not anonymous methods. That means that x => x.Metadata.AdvisorID == advisorId is not compiled into IL at compile time: instead it's compiled into code which builds an equivalent Expression object, which can be passed to a provider such as Entity Framework or LINQ to SQL, in order to generate a database query.
The other part it means to most people is the so-called "syntactic sugar", which effectively calls .Where(), .OrderBy() etc on your behalf:
from a in something
where a.Name == "Bob"
select a;
In both cases, the Queryable class in .NET provides extension methods for building a chain of Expression objects, for example .Where(), .OrderBy(), .Select() etc - these take an IQueryable (either untyped or with a generic parameter) and return another. They lightly wrap an Expression object at each point which represents the query as a whole.
Meaning:
someQueryable.Where(x => x.Id > 3).OrderBy(x => x.Date).Select(x => x.Ref)
Returns an object implementing IQueryable which holds an Expression which looks like:
Select(OrderBy(Where(someQueryable, x => x.Id > 3), x => x.Date), x => x.Ref)
... which is readable by LINQ providers to produce something like:
SELECT Ref FROM someTable WHERE Id > 3 ORDER BY Date
Finally, note that .Where(), .OrderBy() and the like are NOT limited to queryable/LINQ objects. They exist for IEnumerable (and IEnumerable<>), too - but this is not LINQ, and simply performs the operations at the instant that the method is called.

Why is my linq alias out of scope?

I am trying to better understand more complex linq statements. And thanks to a few articles on the web I am coming around. One thing I don't understand is why my query alias is out of context on this statement:
(from query in _context.WebQueries
select query).Where((from qry in _context.WebQueries
join qg in _context.WebQueryGroups on qry.QueryKey equals qg.QueryKey
where qg.QueryGroupNameKey == key
//This is out of scope
select qry.QueryKey).Contains(query.QueryKey));
//if you replaced it with this same problem
.Contains(qry.QueryKey));
I know that I can use an anonymous object call and gain the results I want. I will just have to iterate the object and pull out the List that I want:
(from query in _context.WebQueries
select new {query, key = query.QueryKey})
.Where(q => !(from qry in _context.WebQueries
join qg in _context.WebQueryGroups on qry.QueryKey equals qg.QueryKey
where qg.QueryGroupNameKey == key
select qry.QueryKey).Contains(q.key));
That returns an object with the list I want and the int that I want to reference later in the query.
Why are both query and qry out of scope though? I would much rather just return the linq statement in my method instead of having to parse an object to get the list to return. An article discussing this issue would be great.
I notice you did not get an answer to your specific question, which is as I understand it "what are the scoping rules in queries?"
First off, let's carefully define "scope". The scope of an entity is a region of program text in which a particular entity can be referred to by an unqualified name.
The key to understanding range variable scope is in understanding how queries are translated by the compiler. It is a syntactic translation. When you say:
from r in s where t select u
that is translated syntactically by the compiler into:
((s).Where(r => t)).Select(r => u)
In the translated version there are two rs, both lambda formal parameters, and the regular scoping rules for lambdas apply; each is in scope only for the body of the lambda.
So now you know why you cannot use a range variable outside of a query; that range variable is actually the formal parameter of one or more lambdas, and so is only valid in what is going to be the bodies of those lambdas.
You can learn the rest of the rules by reading the C# specification section on query translation. I note that the rules for "transparent identifier" queries have tricky scoping, so read that section carefully. I've been meaning to write a blog article on that.
UPDATE: I got around to writing that blog entry; you can read it here:
http://ericlippert.com/2014/07/31/transparent-identifiers-part-one/
http://ericlippert.com/2014/08/01/transparent-identifiers-part-two/
Although there is an answer that solves the underlying problem and makes the query work, the actual question isn't answered yet. The answer to the question why the variables are out of scope will probably help you understand LINQ better.
The statement...
from query in _context.WebQueries select query
can be rewritten as:
_context.WebQueries.Select(query => query)
(the part .Select(query => query) is redundant, but I leave it here for sake of the explanation)
this statement can be rewritten as a lambda expression with a method body:
WebQueries.Select(query => { return query; })
(I'll explain later why I don't use _context.WebQueries anymore)
this can be rewritten as an expression with an anonymous method:
WebQueries.Select(delegate(WebQuery query) { return query; })
and this can be rewritten into an expression using a named method:
WebQueries.Select(ReturnArg)
where ReturnArg is this method:
WebQuery ReturnArg(WebQuery query)
{
return query;
}
This is C# history in reverse order: we used to have named methods and delegates only. Later, in order to implement LINQ and other features, anonymous methods and lambda expressions were introduced. But the thing to note here is that under the hood, for the compiler, method syntax still applies, so the lambda expression query => query is nothing but a method having a parameter that is named query. As with all methods, the parameter is scoped to the method body.
In LINQ terminology, this parameter is called range variable, because it will serve as a reference to each successive element in the query.
In short: the range variable is scoped to the LINQ statement in which it is defined. (from query in _context.WebQueries select query) is one LINQ statement. The subsequent Where is a new LINQ statement.
The reason why I stopped using _context.WebQueries is that EF doesn't accept lambda expressions with method body. That is because the method body silently turns the parameter of the Where method from an expression into a Func, and EF only accepts expressions. In fact, the whole statement is never executed in CLR, but translated into SQL and executed by the database engine. However, for the C# compiler the correctness rules still apply. A range variable is a range variable, irrespective of what it's going to be used for.
I don't know what you're trying to accomplish, but this does the same thing:
(from query in _context.WebQueries
from qry in _context.WebQueries
join qg in _context.WebQueryGroups on qry.QueryKey equals qg.QueryKey
where qg.QueryGroupNameKey == request.Key
where qry.QueryKey == query.QueryKey
select query).Distinct();
However, this looks really strange. The join doesn't serve any function, for example.
Why not this?
from query in _context.WebQueries
join qg in _context.WebQueryGroups on query.QueryKey equals qg.QueryKey
where qg.QueryGroupNameKey == request.Key
select query

Why do navigation properties in linq to entities within a subquery not implement IQueryable?

I've recently noticed something odd, navigation properties on an Entitiy do not implement IQueryable,
while as far as i know retrieving a single entity and then chaining operators on navigation property may result in many (1 per item) calls to the database, from the generated code i've seend having one large query with subqueries results (when possible) in a single large query.
However i'm wondering about how it works because the overloads available in a subquery are the same as the ones which would be called on the navigation property outside of the subquery.
Question 1: my guess is that , even if it's on IEnuerable, while the any call itself is part of the expression passed to where, it's then build into the single expression tree generated in where and parsed there and not as a separate expression (since it isn't an expression by itself), is this correct?
Qestion 2: If #1 is correct, how does this work if you create code outside from the expression which may only be made in a delegate at runtime (for example, how would that work if i passed PredicateExprEntityTwo.Compile(), in q5, would that not compile and fail at runtime because the compiler doesn't have knowledge of the usage of the func within an expression at compile time?
Question 3: Assuming i've got #1 and #2 correct, what's the advantage of this design vs taking an expression there? The disadvantage i've ran into is that for business validation i was thinking of having a set of predicates with business logic incorporated in them to filter the same type of entities in many places in a program, however i may want to use those in subqueries too and assuming #2 is right it may be unfeasible to reuse the same one?
I'm sorry if the questions sound a bit confusing but i've only noticed last week that i had IEnumerables overload called in subqueries yet still a single EF query as an output and i'm very curious about how this may work.
public class Class1
{
void Test()
{
Func<Entity1, bool> PredicateFuncEntityOne = i => i.Id == 2;
Expression<Func<Entity1, bool>> PredicateExprEntityOne = i => i.Id == 2;
Func<Entity2, bool> PredicateFuncEntityTwo = i => i.Id == 2;
Expression<Func<Entity2, bool>> PredicateExprEntityTwo = i => i.Id == 2;
using (var Context = new TestModelContainer())
{
// Works as this expects an expression
var q1 = Context.Entity1Set.Where(PredicateExprEntityOne);
// Works but would call the IEnumerable version
var q2 = Context.Entity1Set.Where(PredicateFuncEntityOne);
// This compiles, any on item.Entity2 expects a func on IEnumerable, not IQueryable overload
var q3 = Context.Entity1Set.Where(item => item.Entity2.Any(PredicateFuncEntityTwo));
// This fails for the reason mentioned above
var q4 = Context.Entity1Set.Where(item => item.Entity2.Any(PredicateExprEntityTwo));
// Does this work and if so how is it possible?
var q5 = Context.Entity1Set.Where(item => item.Entity2.Any(PredicateExprEntityTwo.Compile()));
}
}
}
Q1 : I too think this is right.
Q2 : Yes, if you pass Func or any delegate into expression, then compiling of query will fail.
I am not sure about Q3.
But some time back, I had similiar problem while playing around in EF. And I found that casting those relational properties to IQueryable and calling methods Expressions supprisingly worked. But it might be a fluke.

Categories

Resources