using Extension Method or Func in EF lambda expression - c#

I have an extension method that is fairly simple.
When trying to use it in an Entity framework I get this
LINQ to Entities does not recognize the method 'Boolean Between[DateTime](System.DateTime, System.DateTime, System.DateTime, Boolean)'
Many others are getting the same issue and I understand the error. There is always a way to make it work.
I have been digging around trying to figure out how i can re-implement this method and have it be linq to EF friendly.
for this specific method its just checking if one IComparable is between two others. so really it would just expand to
.Where(x=> x.Date >= startDate && x.Date <= endDate)
and all i am really trying to do is make it easier on the eyes and express it like
.Where(x=> x.Date.Between(startDate, endDate))
Being that I am very new to the Func and such Im sure there is a way to approach extension methods (even if written specifically for EF) so that they will be friendly with EF linq
I have done some digging around SO and other sites and come across some interesting answers but not able to get to past the finish line with them.
Thanks in advance!

The query provider is going to be tasked with taking the information provided in the expression that you give it and translating that into SQL. If you take the code that you have and compile it into a C# method then the query provider has no way of inspecting it to see what the original source code was and using that to create corresponding SQL code. You need to use some means of creating Expression objects that it can understand, the easiest means of doing this is generally through lambdas.
What we can do here is create a new extension method for our queries that will accept a query, an Expression that represents the date in question, along with the constant date values that they should be between. Using this we can construct our own expression that represents what the expression would have looked like had you manually typed out the comparisons in the lambda itself:
public static IQueryable<T> WhereBetweenDates<T>(
this IQueryable<T> query,
Expression<Func<T, DateTime>> selector,
DateTime startDate,
DateTime endDate)
{
var predicate = selector.Compose(date => date >= startDate && date <= endDate);
return query.Where(predicate);
}
Here we're using a Compose method. This method accepts one expression that maps a value to another, along with a second expression that maps that value to something else, and it creates a new expression that represents mapping the original value from the first expression to the result of the second. It can do this by replacing all uses of the parameter in the second expression with the body of the first expression:
public static Expression<Func<TFirstParam, TResult>>
Compose<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
Here we're using a method to replace all instances of one expression with another. This can be done using the following helper method:
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
Now I know that this does seem like a lot of code, but the idea here is that you're not using all of this just to write this one method. Everything after that first method is a fundamental building block that you can use to manipulate expressions in reasonably straightforward (and in particular, statically typed) ways. The Compose method can be re-used in all sorts of other contexts to apply a frequently used operation on a constantly changing sub-expression.

You can only use a small subset of functions on types inside the expression that Entity Framework already knows how to handle. Traditionally these are methods like Contains and similar (see this page for a fuller list). Your own extension methods will not be recognized by the parser if they are inside the expression.
However one thing you could do is make a extension method for IQueryable<T> that takes in your range as parameters.
public static IQueryable<T> Between(this IQueryable<T> query, Expression<Func<T, DateTime> selector, DateTime start, DateTime end)
{
//...
}
Now what goes inside the //... would take me a hour or so to figure it all out, and is a little too much to write up for a quick answer on the internet without being paid. But if you learn how to parse and write your own expressions (which is a good skill to have) you may be able to figure out how to do it on your own.
EDIT: Or Servy can figure it out and post it while I am typing up my answer :)

Related

Create Expression<Func<T, TKey>> dynamically

Related To: Create a Lambda Expression With 3 conditions
Please consider this GroupBy statement:
group r by new { r.EmployeeID, r.Name }
If I want to write above GroupBy statement with Lambda version and pass Expression<Func<T, TKey>> to it as parameter, How I can create Expression<Func<T, TKey>>?
I don't have time to walk you through the whole thing, but the general gist is that you'll construct expressions using static methods off of the Expression class.
For example, the new expression will be created by passing constructor information and a series of expressions and such to one of the Expression.New() overloads.
The concept of r => ... is embodied by Expression.Lambda<Func<T, TKey>>(...) where you pass an Expression.Parameter(typeof(T), "r") as the lambda's parameter.
Expression.MakeMemberAccess will help you to produce r.EmployeeId and r.Name.
I find it useful to start by dumping a sample expression in LINQPad with code like this:
void Main()
{
DumpExp(r => new { r.EmployeeID, r.Name });
}
public void DumpExp<TKey>(Expression<Func<Foo, TKey>> expr)
{
expr.Dump();
}
public class Foo
{
public string EmployeeID;
public string Name;
}
That will allow you to inspect the tree and understand what types of expressions make up the tree, and what the values of their properties are. Then you can try writing code to match.
Once you've got an Expression that you think will work, you can call Compile on it to produce a runnable function, which you can use to test its behavior on in-memory objects.
I'm guessing the anonymous type you've got there may be the most difficult part of the problem. If the target framework supports something like Tuples in its GroupBy statements, you will probably be better off using those instead.
There is an oldish project that was designed to enable you to run dynamic LINQ statements built by providing strings to LINQ-like methods. It's called "Dynamic LINQ", and it might suit your needs.
You might also find this library useful. It's supposed to help you build Expression trees with a more fluent syntax. However, it doesn't appear to be under active development.

How to filter records from a db using linq expressions?

I am trying to achieve the following pattern:
Main()
{
...
GetFilteredUsersById(u => u >= 100 && u < 200).Dump();
....
}
public List<UserRecord> FilteredUsersById(Func<int, bool> filter)
{
Expression<Func<UserRecord, bool>> filterExpression = x => filter(x.Id);
return someUserRecordsDb.Where(filterExpression).ToList();
}
public class UserRecord
{
public int Id;
public string Name;
}
Of course, this fails with
NotSupportedException: Method 'System.Object DynamicInvoke(System.Object[])' has no supported translation to SQL.
I understand why the error is happening, but don't know how to fix it.
Below is a pattern that does work, but I'm interested in understanding what changes I need to make to the code to the first pattern above to make it work.
Main()
{
...
GetFilteredUsersById(u => u.Id >= 100 && u.Id < 200).Dump();
....
}
public List<UserRecord> FilteredUsers(Expression<Func<UserRecord, bool>> filter)
{
return someUserRecordsDb.Where(filter).ToList();
}
public class UserRecord
{
public int Id;
public string Name;
}
Thanks for answering my first question here at StackOverflow!
As already you know, LINQ to SQL works by taking your lambdas as expression trees instead of delegates. Then, it analyzes those trees and attempts to produce equivalent SQL code. Obviously, it can't support everything you can possibly write in C#.
In your second snippet, the LINQ provider sees an expression tree that contains this:
u => u.Id >= 100 && u.Id < 200
This is very easy to understand - it involves the && operator, the >= operator and the < operator, all of which are known.
But in your first snippet, the LINQ provider sees an expression tree that contains this instead:
x => filter(x.Id)
This is very different, because it's an invocation of an arbitrary method that's not known to the provider. So now the provider has to look inside that method and see what it contains. If that method had another level of indirection, the provider would have to look even further. And so on.
If your expression tree requires that kind of work, the provider will refuse to do it. So any invocations to arbitrary methods will understandably fail.
Thus, the answer is simple: don't put a level of indirection between the location where you create the expression tree and the actual expression you want translated to SQL, otherwise the LINQ provider will reject it altogether.
There are two things to keep in mind here
1. Expression vs Func
One of the main things you need to understand is the difference between an Expression and a Func or any type of delegate type. In short the expression is passing a tree representation of the lamda, which can be translated into Sql.
There is a great answer that covers this in depth here :
Why would you use Expression<Func<T>> rather than Func<T>?
2. Not all Expressions will Work with Linq-to-Sql
Even if a function can be represented as an expression it does not mean that there will be a proper mapping from the operations being preformed in the lambda expression for the provider that is consuming your linq expression.
This is why you are getting the exception :
NotSupportedException: Method 'System.Object DynamicInvoke(System.Object[])' has no supported translation to SQL.
Here even though it is a valid expression there is no way to convert the operation to sql which is why you get an exception, even though filter would be a valid lambda if passed as an expression and called directly the translation of the statement is that it is trying to call this func filter, which doesn't map directly to anything in sql

Passing Func to Where changes return type from IQueryable to IEnumerable

I have the following code;
IQueryable<MyClass> query = listOfObjects.Where(x => x.SomeProp == 1);
I pass this to a method on a particular API that is expecting an IQueryable, which is fine.
However, I want to dynamically build up the predicate, so I'm using Expression.Lambda to achieve this, and I then .Compile it to turn it back into a Func<MyObject, bool>.
I would have expected that the following would have worked;
Func<MyClass, bool> predicate = x => GetPredicate();
IQueryable<MyClass> query = list.Fields.Where(predicate);
However, passing predicate to Where has changed the return type to IEnumerable<MyClass>, which isn't the type required by the API obviously.
I did (naively) try predicate.AsQueryable(), but the API in question (SharePoint Client Object model) just fails with a generic "Specified method is not supported." error message.
I don't know if this a limitation of the LINQ provider that is behind the scenes, but regardless... I'm keen to understand why pulling the Func out into its own variable and passing it in to Where affects the type inference in the way it does.
IQueryable is using an expression tree to build predicate. So, instead of
Func<MyClass, bool> predicate = x => GetPredicate();
use:
Expression<Func<MyClass, bool>> predicate = x => GetPredicate();
Keep in mind:
While using IQueryable expression tree is built (tree that represents operation (as operands and arguments) made on collection). In order to translate tree into other form (let's say sql query, depends on LINQ proider) translator must know all operands used in to tree. It looks like that translator in service where you are passing IQueryable don't know what does GetPredicate function do (and don't know how to translate it to sql query) so throws Not Supported Exception..
The same thing is with Func instead of Expression. Func is complied version of predicate (stored as delegate) - provider don't know how to translate delegates. When Expression is used, the predicate is stored as tree, so provider can "look inside" an expression and translate it correctly.

Howto use predicates in LINQ to Entities for Entity Framework objects

I'm using LINQ to Entities for Entity Framework objects in my Data Access Layer.
My goal is to filter as much as I can from the database, without applying filtering logic to in-memory results.
For that purpose Business Logic Layer passes a predicate to Data Access Layer.
I mean
Func<MyEntity, bool>
So, if I use this predicate directly, like
public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
return qry = _Context.MyEntities.Where(x => isMatched(x));
}
I'm getting the exception
[System.NotSupportedException] --- {"The LINQ expression node type
'Invoke' is not supported in LINQ to Entities."}
Solution in that question suggests to use AsExpandable() method from LINQKit library.
But again, using
public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
return qry = _Context.MyEntities.AsExpandable().Where(x => isMatched(x));
}
I'm getting the exception
Unable to cast object of type
'System.Linq.Expressions.FieldExpression' to type
'System.Linq.Expressions.LambdaExpression'
Is there way to use predicate in LINQ to Entities query for Entity Framework objects, so that it is correctly transformed it into a SQL statement.
Thank you.
You don't need LinqKit to do this. Just remember to use
Expression<Func<MyEntity, bool>>
instead of
Func<MyEntity, bool>
Something like this:
public IQueryable<MyEntity> GetAllMatchedEntities(Expression<Func<MyEntity, Boolean>> predicate)
{
return _Context.MyEntities.Where(predicate);
}
You have to use Expression because Linq to Entities needs to translate your lambda to SQL.
When you use Func your lambda is compiled to IL but when using Expression it is an expression tree that Linq to Entities can transverse and convert.
This works with expressions that Linq to Entities understands.
If it keeps failing then your expression does something that Linq to Entities can not translate to SQL. In that case I don't think LinqKit will help.
Edit:
There is no conversion needed. Just define the method GetAllMatchedEntities with an Expression parameter and use it in the same way you would with a Func parameter. The compiler does the rest.
There are three ways you can use GetAllMatchedEntities.
1) With an inline lambda expression:
this.GetAllMatchedEntities(x => x.Age > 18)
2) Define your Expression as a field (can be a variable also)
private readonly Expression<Func<MyEntity, bool>> IsMatch = x => x.Age > 18;
...then use it
this.GetAllMatchedEntities(IsMatch)
3) You can create your expression manually. The downsize is more code and you miss the compile-time checks.
public Expression<Func<MyEntity, bool>> IsMatchedExpression()
{
var parameterExpression = Expression.Parameter(typeof (MyEntity));
var propertyOrField = Expression.PropertyOrField(parameterExpression, "Age");
var binaryExpression = Expression.GreaterThan(propertyOrField, Expression.Constant(18));
return Expression.Lambda<Func<MyEntity, bool>>(binaryExpression, parameterExpression);
}
Methods used in Linq to Entities must be canonically mapped by the Linq provider in order to work. Since the Linq provider, EF in your case, was unable to map your predicate to an internal method, it threw an error.
For LINQ scenarios, queries against the Entity Framework involve
mapping certain CLR methods to methods on the underlying data source
through canonical functions. Any method calls in a LINQ to Entities
query that are not explicitly mapped to a canonical function will
result in a runtime NotSupportedException exception being thrown
Source: CLR Method to Canonical Function Mapping (http://msdn.microsoft.com/en-us/library/bb738681.aspx)
You can try to take those methods that ARE mapped and chain them into your Linq expression, or use a stored procedure. But until EF supports all of the CLR, you will be left with having to find a work-around.
On the plus side, each release seems to add a bit more to the canonical list.
Worth reading as a possible work-around: http://msdn.microsoft.com/en-us/library/dd456857.aspx

Using Lambda Expressions trees with IEnumerable

I've been trying to learn more about using Lamba expression trees and so I created a simple example. Here is the code, this works in LINQPad if pasted in as a C# program.
void Main()
{
IEnumerable<User> list = GetUsers().Where(NameContains("a"));
list.Dump("Users");
}
// Methods
public IEnumerable<User> GetUsers()
{
yield return new User{Name = "andrew"};
yield return new User{Name = "rob"};
yield return new User{Name = "chris"};
yield return new User{Name = "ryan"};
}
public Expression<Func<User, bool>> NameContains(string namePart)
{
return u => u.Name.Contains(namePart);
}
// Classes
public class User
{
public string Name { get; set; }
}
This results in the following error:
The type arguments for method 'System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
However if I just substitute the first line in main with this:
IEnumerable<User> list = GetUsers().Where(u => u.Name.Contains("a"));
It works fine. Can tell me what I'm doing wrong, please?
The Enumerable.Where method takes a Func<T, bool>, not an Expression<Func<T, bool>>. Perhaps you're confusing with Queryable.Where, which does take an expression as a parameter... In your case you don't need an expression, you just need a delegate that can be executed against each item in the sequence. The purpose of expressions is (mostly) to be analysed and translated to something else (SQL for instance), to perform the query against an external data source
Change the return type of NameContains from Expression<Func<User, Bool>> to simply Func<User, Bool>. In this situation, there's no need to return the Expression, you actually want to return the compiled delegate. There's a difference between the expression that makes up the lambda, and the lambda (which is a delegate) itself.
If you send a lambda into a method, the method can accept the lambda either as an expression, or as a compiled delegate type, depending on what you specify in the parameters. If the incoming parameter type is an Expression, you can send in something that looks like a delegate, however, if the method is expecting a delegate, you have to give it a compiled delegate, not simply an expression. That being said, you can also do something like:
var certainUsers = GetUsers().Where(NameContains("a").Compile());
Which would compile the expression, and return a Func<User, Bool>.
Lambda expressions can be treated as either code (delegates) or as data (expression trees)
In your example your are attempting to treat the lambda expression as code.
You would use the Expression<> declaration when you want to treat the lambda expression as data.
Why would you want to do this?
Here is a quote from the Book Linq In Action,
" Expression trees can be given to tools at runtime, which use them to guide
their execution or translate them into something else, such as SQL in the case of
LINQ to SQL."
Using Expression Trees allows you to take the lambda expression and convert it to data, this is how Linq to SQL works, it takes the lambda expression or query operators or query expressions and converts them to SQL. You of course can view and modify the created expression tree once converted to sql.
There is a huge difference between Expression and Func<...>, the Func is a pure delegate you can invoke it directly, the expression is a data structure holds information about an expression like information about lambda expression or Linq Syntax (e.g. From x in list where x.Id = 1 select x). The expression cannot be invoked directly it must be compiled first, Expressions is used to convert the expression from a way to another like Link To Sql which converts an expression to Sql statements, the best way to do this to change the return type of the NameContains Method to Func insted of expression cuz you are working with Linq To Objects, but when using with Linq To Sql you can use both Expression or func.

Categories

Resources