【问题标题】:How to Call SQLite User Defined Function with C# LINQ Query如何使用 C# LINQ 查询调用 SQLite 用户定义函数
【发布时间】:2015-05-28 18:41:55
【问题描述】:

使用 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 到 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'.

我可以从这里做什么?

【问题讨论】:

    标签: c# linq sqlite linq-to-entities udf


    【解决方案1】:

    哇哦!我搞定了。

    首先,构建查询时不会调用 DbGetValue 函数,只有在代码中直接调用时才会调用。所以里面的代码是无关紧要的,调用的时候可以直接计算值,不用调用数据库。

    其次,即使该函数在模型中定义为“真实”,如果将返回值更改为双精度而不是浮点数,它也会起作用。不知道为什么。

    第三,你必须将函数绑定到类似这样的连接

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

    这行得通!然后,您可能希望在更方便的位置进行函数绑定,但您明白了。

    祝你好运!

    【讨论】:

      猜你喜欢
      • 2013-12-06
      • 1970-01-01
      • 1970-01-01
      • 2013-11-07
      • 1970-01-01
      • 2021-11-23
      • 2012-12-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多