如何使用 C# LINQ 查询调用 SQLite 用户定义函数
How to Call SQLite User Defined Function with C# LINQ Query
使用 SQLite 和 C#,有人试过在 LINQ 查询中调用 UDF 吗?
在网上搜索,我找到了关于在 C# 中创建 UDF 函数的内容
http://www.ivankristianto.com/howto-make-user-defined-function-in-sqlite-ado-net-with-csharp/
关于在 LINQ to Entities 中调用函数,我这里有解决方法
Calling DB Function with Entity Framework 6
这是我到目前为止得到的。我创建了我的数据库模型和 linq to SQLite。
我将其添加到数据库模型文件中:
<Function Name="fn_CalculateSomething" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo" ReturnType="real">
<Parameter Name="height" Type="real" Mode="In" />
<Parameter Name="depth" Type="real" Mode="In" />
</Function>
我添加这段代码
public partial class MyModelTable {
[DbFunction("MyModel.Store", "fn_CalculateSomething")]
public float? DbGetValue(float height, float depth, float ratio) {
List<ObjectParameter> parameters = new List<ObjectParameter>(3);
parameters.Add(new ObjectParameter("height", height));
parameters.Add(new ObjectParameter("depth", depth));
var lObjectContext = ((IObjectContextAdapter)this).ObjectContext;
var output = lObjectContext.
CreateQuery<float>("MyModel.Store.fn_CalculateSomething(@height, @depth)", parameters.ToArray())
.Execute(MergeOption.NoTracking)
.FirstOrDefault();
return output;
}
}
[SQLiteFunction(Name = "fn_CalculateSomething", Arguments = 2, FuncType = FunctionType.Scalar)]
public class fn_CalculateSomething : SQLiteFunction {
public override object Invoke(object[] args) {
float Height = (float)args[0];
float Depth = (float)args[1];
return Height * Depth;
}
}
如果我尝试这个代码
listBox1.DataSource = (from v in context.MyModelTable
select v.fn_CalculateSomething(5, 5)).ToList();
我收到这个错误
The specified method 'System.Nullable`1[System.Single] fn_CalculateSomething(Single, Single)' on the type 'SQLiteTest.MyModelTable' cannot be translated into a LINQ to Entities store expression because its return type does not match the return type of the function specified by its DbFunction attribute.
如果我尝试这个代码
context.MyModelTable.First().fn_CalculateSomething(5, 5);
我收到这个错误
Unable to cast object of type 'System.Data.Entity.DynamicProxies.MyModelTable_935D452DE6F9E3375A6D180DF5A662168FD2DE164BA93C588D9CDCA1909630EB' to type 'System.Data.Entity.Infrastructure.IObjectContextAdapter'.
我可以从这里做什么?
哇哦!我成功了。
首先,在构建查询时不会调用 DbGetValue 函数,只有在代码中直接调用时才会调用。所以里面的代码是无关紧要的,当它被调用时,你可以直接计算值而不调用数据库。
其次,即使该函数在模型中定义为 "real",如果您将 return 值更改为 double 而不是 float,它也会起作用。不知道为什么。
第三,你必须像这样将函数绑定到连接
public static class ExtensionMethods {
public static void BindFunction(this SQLiteConnection connection, SQLiteFunction function) {
var attributes = function.GetType().GetCustomAttributes(typeof(SQLiteFunctionAttribute), true).Cast<SQLiteFunctionAttribute>().ToArray();
if (attributes.Length == 0) {
throw new InvalidOperationException("SQLiteFunction doesn't have SQLiteFunctionAttribute");
}
connection.BindFunction(attributes[0], function);
}
}
然后这样称呼它
using (NaturalGroundingVideosEntities context = new NaturalGroundingVideosEntities()) {
SQLiteConnection Conn = (SQLiteConnection)context.Database.Connection;
Conn.Open();
Conn.BindFunction(new fn_CalculateSomething());
listBox1.DataSource = (from v in context.RatingCategories
select v.DbGetValue(5, 5, 5)).ToList();
}
这行得通!然后,您可能想在更方便的位置进行函数绑定,但您明白了。
祝你好运!
使用 SQLite 和 C#,有人试过在 LINQ 查询中调用 UDF 吗?
在网上搜索,我找到了关于在 C# 中创建 UDF 函数的内容
http://www.ivankristianto.com/howto-make-user-defined-function-in-sqlite-ado-net-with-csharp/
关于在 LINQ to Entities 中调用函数,我这里有解决方法
Calling DB Function with Entity Framework 6
这是我到目前为止得到的。我创建了我的数据库模型和 linq to SQLite。
我将其添加到数据库模型文件中:
<Function Name="fn_CalculateSomething" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo" ReturnType="real">
<Parameter Name="height" Type="real" Mode="In" />
<Parameter Name="depth" Type="real" Mode="In" />
</Function>
我添加这段代码
public partial class MyModelTable {
[DbFunction("MyModel.Store", "fn_CalculateSomething")]
public float? DbGetValue(float height, float depth, float ratio) {
List<ObjectParameter> parameters = new List<ObjectParameter>(3);
parameters.Add(new ObjectParameter("height", height));
parameters.Add(new ObjectParameter("depth", depth));
var lObjectContext = ((IObjectContextAdapter)this).ObjectContext;
var output = lObjectContext.
CreateQuery<float>("MyModel.Store.fn_CalculateSomething(@height, @depth)", parameters.ToArray())
.Execute(MergeOption.NoTracking)
.FirstOrDefault();
return output;
}
}
[SQLiteFunction(Name = "fn_CalculateSomething", Arguments = 2, FuncType = FunctionType.Scalar)]
public class fn_CalculateSomething : SQLiteFunction {
public override object Invoke(object[] args) {
float Height = (float)args[0];
float Depth = (float)args[1];
return Height * Depth;
}
}
如果我尝试这个代码
listBox1.DataSource = (from v in context.MyModelTable
select v.fn_CalculateSomething(5, 5)).ToList();
我收到这个错误
The specified method 'System.Nullable`1[System.Single] fn_CalculateSomething(Single, Single)' on the type 'SQLiteTest.MyModelTable' cannot be translated into a LINQ to Entities store expression because its return type does not match the return type of the function specified by its DbFunction attribute.
如果我尝试这个代码
context.MyModelTable.First().fn_CalculateSomething(5, 5);
我收到这个错误
Unable to cast object of type 'System.Data.Entity.DynamicProxies.MyModelTable_935D452DE6F9E3375A6D180DF5A662168FD2DE164BA93C588D9CDCA1909630EB' to type 'System.Data.Entity.Infrastructure.IObjectContextAdapter'.
我可以从这里做什么?
哇哦!我成功了。
首先,在构建查询时不会调用 DbGetValue 函数,只有在代码中直接调用时才会调用。所以里面的代码是无关紧要的,当它被调用时,你可以直接计算值而不调用数据库。
其次,即使该函数在模型中定义为 "real",如果您将 return 值更改为 double 而不是 float,它也会起作用。不知道为什么。
第三,你必须像这样将函数绑定到连接
public static class ExtensionMethods {
public static void BindFunction(this SQLiteConnection connection, SQLiteFunction function) {
var attributes = function.GetType().GetCustomAttributes(typeof(SQLiteFunctionAttribute), true).Cast<SQLiteFunctionAttribute>().ToArray();
if (attributes.Length == 0) {
throw new InvalidOperationException("SQLiteFunction doesn't have SQLiteFunctionAttribute");
}
connection.BindFunction(attributes[0], function);
}
}
然后这样称呼它
using (NaturalGroundingVideosEntities context = new NaturalGroundingVideosEntities()) {
SQLiteConnection Conn = (SQLiteConnection)context.Database.Connection;
Conn.Open();
Conn.BindFunction(new fn_CalculateSomething());
listBox1.DataSource = (from v in context.RatingCategories
select v.DbGetValue(5, 5, 5)).ToList();
}
这行得通!然后,您可能想在更方便的位置进行函数绑定,但您明白了。
祝你好运!