Господа программисты, на днях столкнулся с небольшой проблемой. Не удается создать пользовательскую функцию в SQLite на C#.NET так, чтобы она работала, как задумано. Функция скалярная, сравнивает две строки на схожесть по алгоритму LongestCommonSubsequence с проекта
DuoVia.FuzzyStrings. Долго искал пример кода, где пояснялось бы, как это сделать, но везде описывались C-style функции (имеется ввиду sqlite_create_function() из сишного интерфейса к ядру sqlite).
В итоге нашел только вот это:
Как подружить Linq-to-Entities и Regex. Там (ближе к началу) только скалярная функция описывалась, но мне пока только это и надо.
Все выглядело понятно и просто, поэтому я сделал по такому же принципу:
//Создание функции
public class CloseToSQLiteFunction : SQLiteFunction
{
public static SQLiteFunctionAttribute GetAttribute()
{
return new SQLiteFunctionAttribute("CLOSETO", 2, FunctionType.Scalar);
}
public override object Invoke(object[] args)
{
try
{
return FuzzyStrings.LongestCommonSubsequenceExtensions.LongestCommonSubsequence(args[0].ToString(), args[1].ToString()).Item2;
}
catch (Exception ex)
{
return ex;
}
}
}
//***Разный код***//
//Добавление функции в базу при ее создании или подключении:
sql.DB_Conn.BindFunction(CloseToSQLiteFunction.GetAttribute(), new CloseToSQLiteFunction());
Так вот, в дальнейшем эта функция должна принимать 2 аргумента типа String и выдавать Double в запросах типа:
SELECT * FROM BaseTable WHERE CLOSETO('...какая-то строка...',Column1) > 0.33;
SELECT CLOSETO('...какая-то строка...',Column1) from BaseTable
Но и в режиме отладки и в любом другом она ДЕЙСТВИТЕЛЬНО создана, как скалярная функция с двумя входными параметрами, НО один из аргументов ВСЕГДА равен DbNull, и функция CLOSETO всегда возвращает 0.0d.
Пример кода:
static public T Execute<T>(string SQL_Query, params object[] fmtParams)
{
using (var comm = new SQLiteCommand(string.Format(SQL_Query, fmtParams), DB_Conn))
try
{
return (T)Convert.ChangeType(comm.ExecuteScalar(), typeof(T));
}
catch (InvalidCastException)
{
return default(T);
}
}
//***Разный код***//
//...
long myID = Execute<long>("select ID from Person where closeto('{0}',PersonName) > 0.33;", PersonName); //Всегда выдает 0!
//...
Что может быть причиной такого поведения функции?
Введу некоторое пояснение к первому участку кода:
//Создание функции
public class CloseToSQLiteFunction : SQLiteFunction
{
public static SQLiteFunctionAttribute GetAttribute()
{
return new SQLiteFunctionAttribute("CLOSETO", 2, FunctionType.Scalar);
}
//Режим отладки показывает, что args[0] - всегда имеет тип DbNull, несмотря на то, что функции передается две строки
//Запрос: string.Format("select closeto(FirstName||' '||SecondName||' '||ThirdName,'{0}') as Closes from Person",PersonName);
//PersonName - строка, содержащая исключительно символы [A-Za-zА-Яа-я0-9].
public override object Invoke(object[] args)
{
try
{
return FuzzyStrings.LongestCommonSubsequenceExtensions.LongestCommonSubsequence(args[0].ToString(), args[1].ToString()).Item2;
}
catch (Exception ex)
{
return ex;
}
}
}