I know have this simple lambda query(not sure if this one called a query)
var person = db.People.Where(a => a.PersonId == id).FirstOrDefault();
I have a question because i don't know anything about lambda. What is the purpose of => and what is the value of that in linq if it is converted to linq?.
For my basic knowledge this might the converted linq query
var person = (from p in db.Person where p.PersonId == id select p).FirstOrDefault();
right?
The =>, which can be read as maps to or is mapped to belongs to the syntax of labda expressions. Informally the syntax of lambda expressions is
(arg_1, arg_2, ..., arg_n) => rhs,
where (arg-1, arg_2, ..., arg_n) is the list of arguments; if there is one argument, the list (arg1) can be abbreviated to arg1. rhs is either an expression of the desired return type, such as in
x => x * x
or a compound statement returning the desired type as follows.
x =>
{
return x * x;
}
The arguments and return type of the lambda expression are not explicitly defined but deduced at compile time. In total,
a => a.PersonId == id
defines function which maps a person a to a boolean value which is generated by evaluating a.PersonId == id, which means that the return value is true if and only if the person's PersonId is equal to id.
The => is the lambda operator, and is part of the syntax for lambda expressions.
On the left of the => are the input parameters for the expression on the right of =>
a=> a.PersonId == id
is like a function that takes a person object and an Id and returns a boolean, i.e.
bool CheckIfIdIsEqual(Person a, int id) {
return a.PersonId == id;
}
Yes, you are right. The expressions where we use => operator are called lambda expressions.
In the lambda calculus, we describe these patterns as tiny functions. In the C# language, we use lambda functions and the => operator to transform data.
var person = db.People.Where(a => a.PersonId == id).FirstOrDefault();
In the above code, we access all the values or data from db.People using the variable a
For more information you can refer:
1.Expression Lambdas
2.C Sharp Lambda Expression
3.Lambda Expression
Related
Generally, when using the conditional operator, here's the syntax:
int x = 6;
int y = x == 6 ? 5 : 9;
Nothing fancy, pretty straight forward.
Now, let's try to use this when assigning a Lambda to a Func type. Let me explain:
Func<Order, bool> predicate = id == null
? p => p.EmployeeID == null
: p => p.EmployeeID == id;
That's the same syntax, and should work? Right? For some reason that doesn't. The compiler gives this nice cryptic message:
Error 1 Type of conditional expression cannot be determined because there is no implicit conversion between 'lambda expression' and 'lambda expression'
I then went ahead and changed the syntax and this way it did work:
Func<Order, bool> predicate = id == null
? predicate = p => p.EmployeeID == null
: predicate = p => p.EmployeeID == id;
I'm just curious as to why it doesn't work the first way?
(Side note: I ended up not needing this code, as I found out that when comparing an int value against null, you just use object.Equals)
You can convert a lambda expression to a particular target delegate type, but in order to determine the type of the conditional expression, the compiler needs to know the type of each of the second and third operands. While they're both just "lambda expression" there's no conversion from one to the other, so the compiler can't do anything useful.
I wouldn't suggest using an assignment, however - a cast is more obvious:
Func<Order, bool> predicate = id == null
? (Func<Order, bool>) (p => p.EmployeeID == null)
: p => p.EmployeeID == id;
Note that you only need to provide it for one operand, so the compiler can perform the conversion from the other lambda expression.
The C# compiler cannot infer the type of the created lambda expression because it processes the ternary first and then the assignment. you could also do:
Func<Order, bool> predicate =
id == null ?
new Func<Order,bool>(p => p.EmployeeID == null) :
new Func<Order,bool>(p => p.EmployeeID == id);
but that just sucks,
you could also try
Func<Order, bool> predicate =
id == null ?
(Order p) => p.EmployeeID == null :
(Order p) => p.EmployeeID == id;
Let me have my own example since I had the same problem, too (with the hope that the example be helpful for others):
My Find method is generic method that gets Expression<Func<T, bool>> as predicate and gives List<T> as output.
I wanted to find countries, but I need all of them if language list was empty, and filtered list, if language list was filled.
First I used the Code as below:
var countries=
Find(languages.Any()
? (country => languages.Contains(country.Language))
: (country => true));
But exactly I get the error :there is no implicit conversion between lambda expression and lambda expression.
The problem was that, we have just two lambda expressions here, and nothing else, for example, what is country => true exactly?? We have to determine the type of at least one of lambda expressions. If just of one of the expressions be determined, then the error will be omitted. But for make the code more readable, I extracted both lambda expressions, and used the variable instead, as below:
Expression<Func<Country, bool>> getAllPredicate = country => true;
Expression<Func<Country, bool>> getCountriesByLanguagePredicate = country => languages.Contains(country.Language);
var countries= Find(languages.Any()
? getCountriesByLanguagePredicate
: getAllPredicate);
I emphasize that, if I just determined one of the expression's type, the error will be fixed.
Just an update - in C# 10, it IS now possible for the compiler to infer the 'natural type' of a lambda, provided that the input type(s) are provided, e.g.
var evenFilter = (int i) => i % 2 == 0; // evenFilter inferred as `Func<int, bool>`
This also means that 0 input Funcs and Actions can be inferred:
var zeroInputFunc = () => 44 % 2 == 0;
var myAction = () => {Console.WriteLine("Foo");};
However, this won't work:
var filter = i => i % 2 == 0; << Error: The delegate type could not be inferred
As a result, it is now possible to do what the OP originally wanted to do, provided that at least the input types are provided, e.g.
Func<int, bool> myPredicate = selectorFlag
? i => i % 2 == 0
: i => i % 2 == 1;
However, this still isn't permitted:
var myPredicate = selectorFlag
? (int i) => i % 2 == 0
: (int i) => i % 2 == 1;
Error : no implicit conversion between 'lambda expression' and 'lambda expression'
Can someone explain to me why the EF Engine is failing in the following scenario?
It works fine with the following expression:
var data = context.Programs
.Select(d => new MyDataDto
{
ProgramId = d.ProgramId,
ProgramName = d.ProgramName,
ClientId = d.ClientId,
Protocols = d.Protocols.Where(p => p.UserProtocols.Any(u => u.UserId == userId))
.Count(pr => pr.Programs.Any(pg => pg.ProgramId == d.ProgramId))
})
.ToList();
But if I encapsulate some into an extension method:
public static IQueryable<Protocol> ForUser(this IQueryable<Protocol> protocols, int userId)
{
return protocols.Where(p => p.UserProtocols.Any(u => u.UserId == userId));
}
The resulting query:
var data = context.Programs
.Select(d => new MyDataDto
{
ProgramId = d.ProgramId,
ProgramName = d.ProgramName,
ClientId = d.ClientId,
Protocols = d.Protocols.ForUser(userId)
.Count(pr => pr.Programs.Any(pg => pg.ProgramId == d.ProgramId))
})
.ToList();
Fails with the exception: LINQ to Entities does not recognize the method 'System.Linq.IQueryable1[DAL.Protocol] ForUser(System.Linq.IQueryable1[DAL.Protocol], Int32)' method, and this method cannot be translated into a store expression.
I would expect the EF Engine to build the entire expression tree, chaining the necessary expressions and then generate the SQL. Why doesn't it do that?
This is happening because the call to ForUser() is being made inside of the expression tree that the C# compiler builds when it sees the lambda you pass into Select. Entity Framework tries to figure out how to convert that function into SQL, but it can't invoke the function for a few reasons (e.g. d.Protocols does not exist at the moment).
The simplest approach that works for a case like this is to have your helper return a criteria lambda expression, and then pass that into the .Where() method yourself:
public static Expression<Func<Protocol, true>> ProtocolIsForUser(int userId)
{
return p => p.UserProtocols.Any(u => u.UserId == userId);
}
...
var protocolCriteria = Helpers.ProtocolIsForUser(userId);
var data = context.Programs
.Select(d => new MyDataDto
{
ProgramId = d.ProgramId,
ProgramName = d.ProgramName,
ClientId = d.ClientId,
Protocols = d.Protocols.Count(protocolCriteria)
})
.ToList();
More information
When you invoke a LINQ method outside of an expression tree (like you do with context.Programs.Select(...)), the Queryable.Select() extension method actually gets invoked, and its implementation returns an IQueryable<> that represents the extension method getting called on the original IQueryable<>. Here's the implementation of Select, for instance:
public static IQueryable<TResult> Select<TSource,TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector) {
if (source == null)
throw Error.ArgumentNull("source");
if (selector == null)
throw Error.ArgumentNull("selector");
return source.Provider.CreateQuery<TResult>(
Expression.Call(
null,
GetMethodInfo(Queryable.Select, source, selector),
new Expression[] { source.Expression, Expression.Quote(selector) }
));
}
When the queryable's Provider has to generate actual data from the IQueryable<>, it analyzes the expression tree and tries to figure out how to interpret those method calls. Entity Framework has built-in knowledge of many LINQ-related functions like .Where() and .Select(), so it knows how to translate those method calls into SQL. However, it doesn't know what to do for methods that you write.
So why does this work?
var data = context.Programs.ForUser(userId);
The answer is that your ForUser method is not implemented like the Select method above: you are not adding an expression to the queryable to represent calling ForUser. Instead, you are returning the result of a .Where() call. From the IQueryable<>'s perspective, it's as if Where() was called directly, and the call to ForUser() never happened.
You can prove this by capturing the Expression property on the IQueryable<>:
Console.WriteLine(data.Expression.ToString());
... which will produce something like this:
Programs.Where(u => (u.UserId == value(Helpers<>c__DisplayClass1_0).userId))
There's no call to ForUser() anywhere in that expression.
On the other hand, if you include the ForUser() call inside of an expression tree like this:
var data = context.Programs.Select(d => d.Protocols.ForUser(id));
... then the .ForUser() method never actually gets invoked, so it never returns an IQueryable<> that knows the .Where() method got called. Instead, the expression tree for the queryable shows .ForUser() getting invoked. Outputting its expression tree would look something like this:
Programs.Select(d => d.Protocols.ForUser(value(Repository<>c__DisplayClass1_0).userId))
Entity Framework has no idea what ForUser() is supposed to do. As far as it's concerned, you could have written ForUser() to do something that's impossible to do in SQL. So it tells you that's not a supported method.
As I mentioned in my comment above, I can't tell why the EF Engine is working the way it is. Therefore, I've tried to find a way to re-write the query so I'll be able to make use of my extension methods.
The tables are:
Program -> 1..m -> ProgramProtocol -> m..1 -> Protocol
ProgramProtocol is just a join table and is not mapped in the model by Entity Framework.
The idea is simple: select "from left", select "from right" and then join the resulted sets for proper filtering:
var data = context.Programs.ForUser(userId)
.SelectMany(pm => pm.Protocols,
(pm, pt) => new {pm.ProgramId, pm.ProgramName, pm.ClientId, pt.ProtocolId})
.Join(context.Protocols.ForUser(userId), pm => pm.ProtocolId,
pt => pt.ProtocolId, (pm, pt) => pm)
.GroupBy(pm => new {pm.ProgramId, pm.ProgramName, pm.ClientId})
.Select(d => new MyDataDto
{
ProgramName = d.Key.ProgramName,
ProgramId = d.Key.ProgramId,
ClientId = d.Key.ClientId,
Protocols = d.Count()
})
.ToList();
The following Entity Framework query runs without error.
Predicate<Program> filterProgram;
if (programId.HasValue)
filterProgram = (p => p.Id == programId && !p.IsDeleted);
else
filterProgram = (p => !p.IsDeleted);
var analytics = (from a in repository.Query<Analytic>()
where (a.Marker == "Open" || a.Marker == "LastTouch") &&
a.EntityType == "Proposal" &&
a.Site == "C"
join p in repository.Query<Program>()
on a.EntityId equals p.Id
//where filterProgram(p)
group a
by new { a.LoginSessionId, a.EntityId, p.Id, p.Name } into g
let f = g.OrderBy(x => x.TimestampUtc).FirstOrDefault(x => x.Marker == "Open")
where f != null
let t = g.FirstOrDefault(x => x.Marker == "LastTouch" && x.TimestampUtc > f.TimestampUtc)
select new
{
ProgramId = g.Key.Id,
Program = g.Key.Name,
ProposalId = g.Key.EntityId,
FirstOpen = f,
LastTouch = (t ?? f).TimestampUtc
}).ToList();
However, if I uncomment the line where filterProgram(p), I get the run-time error:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
I was expecting that LINQ would be able to incorporate my predicate into the query and convert it to SQL. Why am I getting this error, and is there a way to dynamically modify a where predicate this way?
The problem is caused because Entity Framework needs to be able to convert your LINQ query into SQL. Your LINQ query is compiled into a data structure called an Expression tree which is then passed to Entity Framework for conversion to SQL.
You have two options:
Replace your call to filterProgram with a more basic C# expression. Depending on the complexity of filterProgram this may not be possible.
Remove you call to filterProgram, and convert this query to an IEnumerable<T>, maybe by calling .ToList(). You can then further filter the results of this query using filterProgram
Example of 2
var query = /* Your Query With filterProgram commented out */
var resultsFromSql = query.ToList();
var fullyFiltered = resultsFromSql.Select(filterProgram);
Change filterProgram's type to Expression<Func<Program, bool>> and then it should be usable in a LINQ Where clause.
One caveat, however: I managed to get it to work in method chain syntax, but not in query syntax.
For example, this works:
dataContext.Programs.Where (filterProgram)
but this does not:
from p in dataContext.Programs
where filterprogram
(The compiler complains that it cannot resolve method Where, which is available on both IEnumerable and IQueryable.)
In your case, it might be acceptable to replace the line
join p in repository.Query<Program>()
with
join p in repository.Query<Program>().Where(filterProgram)
In Linq to Entities it is not possible to call an external method without converting the query to IEnumerable. Thus, since filterProgram is a method, you may not call inside the query.
If possible you may call ToList before calling the FilterProgram and it will work.
Another option maybe inserting the logic of filterProgram into the query.
The problem is that linq2entities tries to translate the expression tree to SQL your expression tree has an invocation of the method Invoke on a delegate type (filterProgram)
however there's nothing stopping you from inlining that predicate
var id= programId.HasValue ? programId.GetValueOrDefault() : -1;
var analytics = (from a in repository.Query<Analytic>()
where (a.Marker == "Open" || a.Marker == "LastTouch") &&
a.EntityType == "Proposal" &&
a.Site == "C"
join p in repository.Query<Program>()
on a.EntityId equals p.Id
where !p.IsDeleted && (!hasValue || p.Id == id)
....
This assumes that -1 is an invalid programId
Is is possible to have a local variable in an anonymous c# methods, i.e. in the following code I would like to perform the count only once.
IQueryable<Enquiry> linq = db.Enquiries;
if(...) linq = linq.Where(...);
if(...) linq = linq.Where(e =>
(x <= (from p in db.Orders where p.EnquiryId == e.Id select p).Count() &&
(from p in db.Orders where p.EnquiryId == e.Id select p).Count() <= y));
if(...) linq = linq.Where(...);
var result = (from e in linq select e);
Is there a "let" for anonymous functions?
Update:
Note that I'm adding several Where clauses after this statement so I can't close with a select.
/Niels
Yes, why not?! After all it's a function, just anonymous!
Example:
x => { int y = x + 1; return x + y; }
Or alternatively:
delegate(int x) {
int y = x + 1;
return x + y;
}
So your code can be written as:
... = linq.Where(e => {
var count = (from p in db.Orders where p.EnquiryId == e.Id select p).Count();
return x <= count && count <= y;
});
UPDATE: To clarify things about the comment, it's important to know the difference between anonymous methods and lambda expressions. An anonymous method is just like a normal method, without an explicit name. When you compile it, the compiler generates a normal method with a weird name for you instead, so it will not have any special limitations. However, one representation of an anonymous method is a lambda expression. Lambda expressions can be interpreted in a couple different ways. The first is a delegate. In that way, they are equal to an anonymous method. The second is an expression tree. This way is normally used by LINQ to SQL and some other LINQ providers. They don't execute your expression directly by any means. They parse it as an expression tree and use the tree as input data to generate the equivalent SQL statement to be run on the server. It's not executed like a method and it's not considered an anonymous method. In that case, you can't define a local variable as it's not possible to parse the lambda as an expression tree.
Yes, you can do exactly what you want, in Linq to objects and Linq to SQL.
There is a let in Linq, allowing you to give a name to an intermediate result in the middle of your query, just as you want to. Based on your example:
... = from e in linq
let count = (from p in db.Orders where p.EnquiryId == e.Id select p).Count()
where (x <= count) && (count <= y)
select e;
By the way, I think there was something syntactically erroneous about your original example, which is easier to spot when the count is just a name:
where (x <= count) && /* <= */ (count <= y);
If you're using Linq to SQL, you won't be able to use Mehrdad Afshari's answer. Your LINQ expressions need to be Expression Trees, and those don't support the anonymous delegate syntax.
Neither will you be able to create your delegate elsewhere and call it from inside the lambda - Linq to SQL only allows certain operations to be performed in the body of the query, and calling a delegate isn't one of them.
Your best bet, assuming you're using Linq to SQL (as it appears given your example), is to bring down the count in one query, then capture the count variable in the query that requires the count.
The Where method takes a Func so what you're passing in there in the second part ins't actually a method, but just a bool expression. My suggestion would be to have an actual method that returns a bool, that takes in the paremeters you need, and in your call to the Where method you just do something like this Where(p=> MyMethod(p,...))
I've run into a similar problem. The solution is to create a custom expression tree generating method.
I asked my question on MSDN-forums. Please see the question and answer here: Reusing Where expressions.
This may give you an idea on how to proceed, but I must admit that custom expression trees are not for the faint-hearted ;-)
With a little background in Scheme you would know that 'let' is just syntax sugar for defining a lambda and invoking it.
So with that knowledge, lets see how it can be done.
(count => x <= count && count <= y)
((from p in db.Orders
where p.EnquiryId == e.Id
select p).Count())
As a bonus, it looks like Scheme too :)
Disclaimer: I did not test this snippet, but there is no reason it should not work. Personally, I would just use the 'let' construct provided in LINQ.
Update:
It does not work... :(
Generally, when using the conditional operator, here's the syntax:
int x = 6;
int y = x == 6 ? 5 : 9;
Nothing fancy, pretty straight forward.
Now, let's try to use this when assigning a Lambda to a Func type. Let me explain:
Func<Order, bool> predicate = id == null
? p => p.EmployeeID == null
: p => p.EmployeeID == id;
That's the same syntax, and should work? Right? For some reason that doesn't. The compiler gives this nice cryptic message:
Error 1 Type of conditional expression cannot be determined because there is no implicit conversion between 'lambda expression' and 'lambda expression'
I then went ahead and changed the syntax and this way it did work:
Func<Order, bool> predicate = id == null
? predicate = p => p.EmployeeID == null
: predicate = p => p.EmployeeID == id;
I'm just curious as to why it doesn't work the first way?
(Side note: I ended up not needing this code, as I found out that when comparing an int value against null, you just use object.Equals)
You can convert a lambda expression to a particular target delegate type, but in order to determine the type of the conditional expression, the compiler needs to know the type of each of the second and third operands. While they're both just "lambda expression" there's no conversion from one to the other, so the compiler can't do anything useful.
I wouldn't suggest using an assignment, however - a cast is more obvious:
Func<Order, bool> predicate = id == null
? (Func<Order, bool>) (p => p.EmployeeID == null)
: p => p.EmployeeID == id;
Note that you only need to provide it for one operand, so the compiler can perform the conversion from the other lambda expression.
The C# compiler cannot infer the type of the created lambda expression because it processes the ternary first and then the assignment. you could also do:
Func<Order, bool> predicate =
id == null ?
new Func<Order,bool>(p => p.EmployeeID == null) :
new Func<Order,bool>(p => p.EmployeeID == id);
but that just sucks,
you could also try
Func<Order, bool> predicate =
id == null ?
(Order p) => p.EmployeeID == null :
(Order p) => p.EmployeeID == id;
Let me have my own example since I had the same problem, too (with the hope that the example be helpful for others):
My Find method is generic method that gets Expression<Func<T, bool>> as predicate and gives List<T> as output.
I wanted to find countries, but I need all of them if language list was empty, and filtered list, if language list was filled.
First I used the Code as below:
var countries=
Find(languages.Any()
? (country => languages.Contains(country.Language))
: (country => true));
But exactly I get the error :there is no implicit conversion between lambda expression and lambda expression.
The problem was that, we have just two lambda expressions here, and nothing else, for example, what is country => true exactly?? We have to determine the type of at least one of lambda expressions. If just of one of the expressions be determined, then the error will be omitted. But for make the code more readable, I extracted both lambda expressions, and used the variable instead, as below:
Expression<Func<Country, bool>> getAllPredicate = country => true;
Expression<Func<Country, bool>> getCountriesByLanguagePredicate = country => languages.Contains(country.Language);
var countries= Find(languages.Any()
? getCountriesByLanguagePredicate
: getAllPredicate);
I emphasize that, if I just determined one of the expression's type, the error will be fixed.
Just an update - in C# 10, it IS now possible for the compiler to infer the 'natural type' of a lambda, provided that the input type(s) are provided, e.g.
var evenFilter = (int i) => i % 2 == 0; // evenFilter inferred as `Func<int, bool>`
This also means that 0 input Funcs and Actions can be inferred:
var zeroInputFunc = () => 44 % 2 == 0;
var myAction = () => {Console.WriteLine("Foo");};
However, this won't work:
var filter = i => i % 2 == 0; << Error: The delegate type could not be inferred
As a result, it is now possible to do what the OP originally wanted to do, provided that at least the input types are provided, e.g.
Func<int, bool> myPredicate = selectorFlag
? i => i % 2 == 0
: i => i % 2 == 1;
However, this still isn't permitted:
var myPredicate = selectorFlag
? (int i) => i % 2 == 0
: (int i) => i % 2 == 1;
Error : no implicit conversion between 'lambda expression' and 'lambda expression'