7

I have the following linq expression in lambda syntax:

var myValue = 6;
var from = 2;
var to = 8;

var res = MyList.Where(m => m.person.Id == person.Id
                         && IsBetween(myValue, from, to))
                .Select(x => new Person { blah blah blah })
                .ToList());

IsBetween is simple generic helper method to see whether I have something in between:

public bool IsBetween<T>(T element, T start, T end)
{
    return Comparer<T>.Default.Compare(element, start) >= 0
        && Comparer<T>.Default.Compare(element, end) <= 0;
}

Now I get this error, and I don't know hot to get around it:

LINQ to Entities does not recognize the method 'Boolean IsBetween[Decimal](System.Decimal, System.Decimal, System.Decimal)' method, and this method cannot be translated into a store expression.

David S.
  • 5,965
  • 2
  • 40
  • 77
codingjoe
  • 707
  • 5
  • 15
  • 32
  • How would that be useful anyway, given that `myValue`, `from` and `to` are all hard-coded, and not part of your entity? Please give a more realistic example. – Jon Skeet Nov 16 '13 at 18:46
  • possible duplicate of [all of these](https://www.google.co.uk/search?q=C%23+LINQ+to+Entities+does+not+recognize+the+method). – Rawling Nov 16 '13 at 18:46
  • Those values are just hardcoded for the example. The values are passed as arguments on my method signature. – codingjoe Nov 16 '13 at 18:47
  • It is really interesting...prior to writing my question I was searching for similar questions. Now I may be very wrong, but the other questions were built-in calls like tostring() etc. I was wondering whether a custom method like IsBetween was different since it is custom made by me. – codingjoe Nov 16 '13 at 18:51
  • 1
    possible duplicate of [LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression](http://stackoverflow.com/questions/5899683/linq-to-entities-does-not-recognize-the-method-system-string-tostring-method) – Thomas Levesque Nov 16 '13 at 18:51
  • Take a look at this approach as well https://stackoverflow.com/questions/47342632/linq-to-entities-does-not-recognize-the-method-boolean-containsany/47342694#47342694 – NoWar Nov 17 '17 at 03:13
  • Related posts - [LINQ to Entities does not recognize the method](https://stackoverflow.com/q/7259567/465053) & [Entity Framework Specification Pattern Implementation](https://stackoverflow.com/q/2352764/465053) – RBT Mar 01 '19 at 11:31

2 Answers2

13

You cannot call arbitrary methods from within a LINQ to Entities query, as the query is executed within the SQL database engine. You can only call methods which the framework can translate into equivalent SQL.

If you need to call an arbitrary method, the query operator calling the method call will need to be preceded by an AsEnumerable() operator such that the call happens client-side. Be aware that by doing this, all results to the left-hand side of AsEnumerable() will potentially be loaded into memory and processed.

In cases where the method you are calling is short enough, I would simply inline the logic. In your case, you would also need to drop the Comparer calls, and IsBetween(myValue, from, to) would simply become myValue >= from && myValue <= to.

Mike Strobel
  • 25,075
  • 57
  • 69
  • using `AsEnumerable` is the solution we found in many other references and it is a short but not efficient solution when all the data is pulled from the server to the client. I would like to see some solution using Expression tree here. – King King Nov 16 '13 at 18:53
  • I found that searching on other sites as well. I may have to rewrite my expression then. :( – codingjoe Nov 16 '13 at 18:54
  • 2
    Your method is short enough that you could inline the logic. I would just do that. However, you'll have to replace the comparer calls with equivalent relational operators (`<`, `>`, etc.). – Mike Strobel Nov 16 '13 at 18:54
2

In Addition to this, if you want to pass the values to IsBetween method from MyList.

Take a wrapper class (here Person) contains the same properties to be passed to the method. and do something like this:

var res = MyList.Where(m => m.person.Id == person.Id)
            .Select(x => new Person { p1 = x.p1, p2 = x.p2 })
            .AsEnumerable()
            .where(x => (IsBetween(x.p1, x.p2)))
            .ToList());
Mafii
  • 7,227
  • 1
  • 35
  • 55
Sujeet
  • 91
  • 1
  • 2
  • 6