Reputation: 599
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
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