How to build a simple property selector expression in ef6

c# entity-framework expression-trees linq

Question

How can I develop a similar property selector for entity framework?

public static List<T> StandardSearchAlgorithm<T>(this IQueryable<T> queryable, Func<T, string> property, string query)
{

    return queryable.Where(e => property(e).ToLower().IndexOf(query) > -1).ToList();

}

I'd want the calling code to be as clear and simple as possible, like this:

var usernameResults = _db.Users.StandardSearchAlgorithm(u => u.Username, query);

I get an error that reads, "LINQ to Entities does not support the LINQ expression node type 'Invoke'." I am unable to figure out how to build the phrase.

UPDATE:

Here is the code I came up with using MBoros' response as a guide. Very well done.

Expression trees work by breaking up what you normally write in code (such as "e => e.Username.IndexOf(query)") into a series of objects: "e" gets its own object, "Username" gets its own object, "IndexOf()" gets its own object, the "query" constant gets its own object, and so on. This is the key to understanding expression trees. Being aware that you may utilize a number of static methods on theExpression class to produce other varieties of these objects, as seen below.

    PropertyInfo pinfo = (PropertyInfo)((MemberExpression)property.Body).Member;
    ParameterExpression parameter = Expression.Parameter(typeof(T), "e");
    MemberExpression accessor = Expression.Property(parameter, pinfo);
    ConstantExpression queryString = Expression.Constant(query, typeof(string));
    ConstantExpression minusOne = Expression.Constant(-1, typeof(int));
    MethodInfo indexOfInfo = typeof(string).GetMethod("IndexOf", new[] { typeof(string) }); // easiest way to do this
    Expression indexOf = Expression.Call(accessor, indexOfInfo, queryString);
    Expression expression = Expression.GreaterThan(indexOf, minusOne);
    Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(expression, parameter);
    //return predicate.Body.ToString(); // returns "e => e.Username.IndexOf(query) > -1" which is exactly what we want.

    var results = queryable.Where(predicate).ToList();
    return results;

I now have a serious issue, but I will address it in a different inquiry. My actual question is this:

public static List<T> StandardSearchAlgorithm<T>(this IQueryable<T> queryable, Func<T, string> property, string query)
{

    return queryable.Where(e => property(e).IndexOf(query) > -1).Select(e=> new { Priority = property(e).IndexOf(query), Entity = e } ).ToList();

}

I must create an expression that returns an Anonymous Type, thus! I still have to write an expression that yields a new object, even if I design a class to assist. But I'll address this in a another query.

1
1
7/13/2015 1:01:22 PM

Accepted Answer

In sql, it is not possible to call CLR delegates that easily. The property selection may, however, be sent in as an Expression tree, so your signature would be:

public static List<T> StandardSearchAlgorithm<T>(this IQueryable<T> queryable, Expression<Func<T, string>> property, string query)

The same would apply to calling. However, now that you have an expression in your possession, you might consider this response: Pass an expression parameter to another expression as an argument. It provides you with the resources to easily nest one expression tree within another. For you, it would seem as follows:

Expression<Func<T, bool>> predicate = e => property.AsQuote()(e).Contains(query);
predicate = predicate.ResolveQuotes();
return queryable.Where(predicate).ToList();

Once there, you may still use the.ToLower command (). (use) is called by contains(). instead of the, contains. 1) IndexOf()> Actually, this is tough. If the database is configured to CI (case insensitive), which is its default collation, it will do the comparison in this manner. I would choose it if there are no restrictions and you may change the database collation. You may skip the.ToLower() function in this scenario. If not, have a look at this response: https://stackoverflow.com/a/2433217/280562

2
5/23/2017 12:06:04 PM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow