130

I'm getting the following error when trying to do a linq query:

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

I've read lots of previous questions where people get the same error, and if I understand this correctly it's because LINQ to Entities requires the whole linq query expression to be translated to a server query, and therefore you can't call an outside method in it. I haven't been able to convert my scenario into something that works yet, and my brain is starting to melt down, so I was hoping someone could point me in the right direction. We're using Entity Framework and the specification pattern (and I'm new to both).

Here's the code that uses the specification:

ISpecification<Charity> specification = new CharitySearchSpecification(charityTitle, charityReference);

charities = charitiesRepository.Find(specification).OrderBy(p => p.RegisteredName).ToList();

Here's the linq expression:

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    return p => p.IsCharityMatching(this.charityName, this.charityReference);
}

Here's the IsCharityMatching method:

public bool IsCharityMatching(string name, string referenceNumber)
{
    bool exists = true;

    if (!String.IsNullOrEmpty(name))
    {
        if (!this.registeredName.ToLower().Contains(name.ToLower()) &&
            !this.alias.ToLower().Contains(name.ToLower()) &&
           !this.charityId.ToLower().Contains(name.ToLower()))
        {
            exists = false;
        }
    }

    if (!String.IsNullOrEmpty(referenceNumber))
    {
        if (!this.charityReference.ToLower().Contains(referenceNumber.ToLower()))
        {
            exists = false;
        }
    }

    return exists;
}

Let me know if you need any more information.

Many thanks,

Annelie

Nivid Dholakia
  • 5,008
  • 4
  • 28
  • 55
annelie
  • 2,459
  • 6
  • 23
  • 39
  • check [this answer](http://stackoverflow.com/questions/7200792/combining-c-code-and-database-code-in-a-specification/7201352#7201352) – Eranga Aug 31 '11 at 15:52
  • Will check this out as well, thanks! – annelie Aug 31 '11 at 16:01
  • 1
    It'd be nice to see how you are using `Find()` when how do you use `IsSatisfied()` inside of it. – Alisson Reinaldo Silva Mar 19 '17 at 03:25
  • Related posts - [LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression](https://stackoverflow.com/q/5899683/465053) & [Entity Framework Specification Pattern Implementation](https://stackoverflow.com/q/2352764/465053) – RBT Mar 01 '19 at 11:36

5 Answers5

137

As you've figured out, Entity Framework can't actually run your C# code as part of its query. It has to be able to convert the query to an actual SQL statement. In order for that to work, you will have to restructure your query expression into an expression that Entity Framework can handle.

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    string name = this.charityName;
    string referenceNumber = this.referenceNumber;
    return p => 
        (string.IsNullOrEmpty(name) || 
            p.registeredName.ToLower().Contains(name.ToLower()) ||
            p.alias.ToLower().Contains(name.ToLower()) ||
            p.charityId.ToLower().Contains(name.ToLower())) &&
        (string.IsNullOrEmpty(referenceNumber) ||
            p.charityReference.ToLower().Contains(referenceNumber.ToLower()));
}
StriplingWarrior
  • 142,651
  • 26
  • 235
  • 300
1

I got the same error in this code:

 var articulos_en_almacen = xx.IV00102.Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

this was the exactly error:

System.NotSupportedException: 'LINQ to Entities does not recognize the method 'Boolean Exists(System.Predicate`1[conector_gp.Models.almacenes_por_sucursal])' method, and this method cannot be translated into a store expression.'

I solved this way:

var articulos_en_almacen = xx.IV00102.ToList().Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

I added a .ToList() before my table, this decouple the Entity and linq code, and avoid my next linq expression be translated

NOTE: this solution isn't optimal, because avoid entity filtering, and simply loads all table into memory

Ing. Gerardo Sánchez
  • 1,577
  • 14
  • 14
  • 5
    Most of time this the easiest solution but to not load all the object i usually make a anonymous select before the .ToList() with just what i need... xx.Select(x=> new { x.Id, x.DateTimeUpdate}).ToList().Select(x=> new { x.Id, DateTimeUpdate = x.DateTimeUpdate.ToString("dd/MM/yyyy") }) – Diógenes Jan 22 '19 at 17:57
1

I ran into the same problem today, this was the first link I hit. However I was not looking for verifying my query. So if somebody else has the same issue and are looking for this solution it is added here. My issue was in another link.

It is the most common exception occurs when working with entity framework and converting data inside IQueryable result for filtering.

using (var context = new CustomerContext())
{
    var item = context.InvoiceItems
        .Where(i => i.Code == code.ToString())
        .FirstOrDefault();
}

Several solutions exist. Move ToString() call to a separate line.

using (var context = new CustomerContext())
{
    string codeStr = code.ToString();
    var item = context.InvoiceItems
        .Where(i => i.Code == codeStr)
        .FirstOrDefault();
}

Use EF Extension Method,

using (var context = new CustomerContext())
{
    var item = context.InvoiceItems
        .Where(i => i.Code == SqlFunctions.StringConvert(code))
        .FirstOrDefault();
}

Convert IQueryable result to IEnumerable before Filtering

using (var context = new CustomerContext())
{
    var item = context.InvoiceItems.AsEnumerable()
        .Where(i => i.Code == code.ToString())
        .FirstOrDefault();
}
JTIM
  • 2,645
  • 31
  • 69
0

If anyone is looking for a VB.Net answer (as I was initially), here it is:

Public Function IsSatisfied() As Expression(Of Func(Of Charity, String, String, Boolean))

Return Function(charity, name, referenceNumber) (String.IsNullOrWhiteSpace(name) Or
                                                         charity.registeredName.ToLower().Contains(name.ToLower()) Or
                                                         charity.alias.ToLower().Contains(name.ToLower()) Or
                                                         charity.charityId.ToLower().Contains(name.ToLower())) And
                                                    (String.IsNullOrEmpty(referenceNumber) Or
                                                     charity.charityReference.ToLower().Contains(referenceNumber.ToLower()))
End Function
Mik
  • 3,370
  • 1
  • 23
  • 15
-1

I got the same error in this code:

Solution

IQuerable to

.toList() is best option

Sameer Bahad
  • 503
  • 5
  • 4