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


Solution 1:

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()));
}

Solution 2:

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

Solution 3:

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();
}