Subodh Chettri
Subodh Chettri

Reputation: 599

Linq to Entities: does not recognize the method

I am trying to use Levenshtein Distance Linq select query (as shown below) it throws an exception.

IEnumerable<Host> closeNeighbours = (from h in _dbContext.People
                                         let lD = Utilities.LevenshteinDistance(lastName, h.LastName)
                                         let length = Math.Max(h.LastName.Length, LastName.Length)
                                         let score = 1.0 - (double)lD / length
                                         where score > fuzziness

                                         select h);



public static int LevenshteinDistance(string src, string dest)
{
    int[,] d = new int[src.Length + 1, dest.Length + 1];
    int i, j, cost;
    char[] str1 = src.ToCharArray();
    char[] str2 = dest.ToCharArray();

    for (i = 0; i <= str1.Length; i++)
    {
        d[i, 0] = i;
    }
    for (j = 0; j <= str2.Length; j++)
    {
        d[0, j] = j;
    }
    for (i = 1; i <= str1.Length; i++)
    {
        for (j = 1; j <= str2.Length; j++)
        {

            if (str1[i - 1] == str2[j - 1])
                cost = 0;
            else
                cost = 1;

            d[i, j] =
                Math.Min(
                    d[i - 1, j] + 1,              // Deletion
                    Math.Min(
                        d[i, j - 1] + 1,          // Insertion
                        d[i - 1, j - 1] + cost)); // Substitution

            if ((i > 1) && (j > 1) && (str1[i - 1] ==
                str2[j - 2]) && (str1[i - 2] == str2[j - 1]))
            {
                d[i, j] = Math.Min(d[i, j], d[i - 2, j - 2] + cost);
            }
        }
    }

    return d[str1.Length, str2.Length];
}

It does not seem to work. Any alternative?

Exception: System.NotSupportedException was unhandled by user code Message=LINQ to Entities does not recognize the method 'Int32 LevenshteinDistance(System.String, System.String)' method, and this method cannot be translated into a store expression. Source=System.Data.Entity

Upvotes: 3

Views: 2966

Answers (1)

Anthony Pegram
Anthony Pegram

Reputation: 126794

You cannot use that function in a entity framework query, as EF will not be able to translate it to the appropriate TSQL. You'll have to bring the source sequence into memory, allowing whatever filters are applicable at the database, and then perform the rest in linq-to-objects. It's only a subtle change.

var closeNeighbors = from h in db.People.AsEnumerable() // bring into memory
                     // query continued below as linq-to-objects
                     let lD = Utilities.LevenshteinDistance(lastName, h.LastName) 
                     let length = Math.Max(h.LastName.Length, LastName.Length) 
                     let score = 1.0 - (double)lD / length 
                     where score > fuzziness 
                     select h; 

Everything prior to AsEnumerable() will happen at the database. If there are filters generally applicable to People, you can use those prior to the AsEnumerable() invocation. Example

var mixedQuery = db.People
                     .Where(dbPredicate).OrderBy(dbOrderSelector) // at the database
                     .AsEnumerable() // pulled into memory
                     .Where(memoryPredicate).OrderBy(memoryOrderSelector);

Upvotes: 3

Related Questions