使用Entity Framework 4.0/.edmx从c#调用标量函数

jay*_*jay 21 c# user-defined-functions entity-framework-4

我想将我的标量函数映射到我的.edmx但它失败了.我右键单击我的实体框架映射,并从数据库中选择更新模型.它出现在我的模型浏览器中的存储过程文件夹中.

但是,当我想将它添加到Function Imports模型浏览器中的我的文件夹时,消息标量函数不会出现在下拉列表中.有人能帮我吗?

我可以使用旧方法调用标量函数,例如:

dbContext.ExecuteStoreQuery<DateTime?>(
"SELECT dbo.getMinActualLoadDate ({0}, {1}, {2}) AS MyResult", 
LoadPkid, LoadFkStartLoc, TripSheetPkid).First();
Run Code Online (Sandbox Code Playgroud)

但这不是最好的方法.我的经理希望我找到一种能够将标量函数放在"函数导入"文件夹中的方法,这样我就可以使用以下代码而不是前面的代码来调用标量函数:

dbContext.ExecuteFunction("getMinActualLoadDate ", paramList);
Run Code Online (Sandbox Code Playgroud)

我试图添加一个图像来显示我的意思,但由于我的声誉仍然很低,我无法这样做.然而,图像可以在这里找到:http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/756865e5-ff25-4f5f-aad8-fed9d741c05d

谢谢.

Pav*_*kiy 14

我遇到过同样的问题.这里是解决方案我发现自己足够合适(在EF5中测试,但也应该在EF4中工作):

不支持将标量值函数映射到开箱即用,但您可以直接执行它们.

您还可以编辑edmx文件以使edmx为标量值函数生成正确的方法,但如果您将模型与数据库同步,则将删除它.

自己编写标量值函数实现:

string sqlQuery = "SELECT [dbo].[CountMeals] ({0})";
Object[] parameters = { 1 };
int activityCount = db.Database.SqlQuery<int>(sqlQuery, parameters).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

或编辑edmx并添加Xml以用于标量值函数的自定义maping:

<Function Name="CountActivities" Aggregate="false" BuiltIn="false"    NiladicFunction="false" IsComposable="false"   ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
    <CommandText>
        SELECT [dbo].[CountActivities] (@personId)
    </CommandText>
    <Parameter Name="personId" Type="int" Mode="In" />
</Function>
Run Code Online (Sandbox Code Playgroud)

此信息可在此博客文章中找到


dpe*_*ish 7

以下是我对这个问题的解决方案,这几乎就是你的经理所要求的......尽管已经晚了18个月.

作为一种香草方法:

    /// <summary>
    /// Calls a given Sql function and returns a singular value
    /// </summary>
    /// <param name="db">Current DbContext instance</param>
    /// <typeparam name="T">CLR Type</typeparam>
    /// <param name="sql">Sql function</param>
    /// <param name="parameters">Sql function parameters</param>
    /// <param name="schema">Owning schema</param>
    /// <returns>Value of T</returns>
    public T SqlScalarResult<T>(DbContext db, 
                                string sql, 
                                SqlParameter[] parameters,
                                string schema = "dbo") {

        if (string.IsNullOrEmpty(sql)) {
            throw new ArgumentException("function");
        }

        if (parameters == null || parameters.Length == 0) {
            throw new ArgumentException("parameters");
        }

        if (string.IsNullOrEmpty(schema)) {
            throw new ArgumentException("schema");
        }

        string cmdText =
            $@"SELECT {schema}.{sql}({string.Join(",",
                parameters.Select(p => "@" + p.ParameterName).ToList())});";

        // ReSharper disable once CoVariantArrayConversion
        return db.Database.SqlQuery<T>(cmdText, parameters).FirstOrDefault();

    }

}
Run Code Online (Sandbox Code Playgroud)

并作为EF的扩展方法:

namespace System.Data.Entity {

    public static class DatabaseExtensions {

        /// <summary>
        /// Calls a given Sql function and returns a singular value
        /// </summary>
        /// <param name="db">Current DbContext instance</param>
        /// <typeparam name="T">CLR Type</typeparam>
        /// <param name="sql">Sql function</param>
        /// <param name="parameters">Sql function parameters</param>
        /// <param name="schema">Owning schema</param>
        /// <returns>Value of T</returns>
        public static T SqlScalarResult<T>(this Database db, 
                                           string sql, 
                                           SqlParameter[] parameters,
                                           string schema = "dbo") {

            if (string.IsNullOrEmpty(sql)) {
                throw new ArgumentException("sql");
            }

            if (parameters == null || parameters.Length == 0) {
                throw new ArgumentException("parameters");
            }

            if (string.IsNullOrEmpty(schema)) {
                throw new ArgumentException("schema");
            }

            string cmdText =
                $@"SELECT {schema}.{sql}({string.Join(",", 
                    parameters.Select(p => "@" + p.ParameterName).ToList())});";

            // ReSharper disable once CoVariantArrayConversion
            return db.SqlQuery<T>(cmdText, parameters).FirstOrDefault();

        }

    }

}
Run Code Online (Sandbox Code Playgroud)

虽然它不吸烟,但我建议在严重使用之前进行单元测试.

  • 这应该标记为已接受的答案.此方法非常有效,并且还使用了SqlParameters. (2认同)

spa*_*jce 1

我猜您错过了Edit Function Import可以生成复杂类型的对话框。尝试探索。

在此输入图像描述

如果您已成功创建scalars,您现在可以像这样导航

using (var con = new DatabaseEntities())
{
   long? invoiceNo = con.sp_GetInvoiceMaxNumber(code.Length + 2).First();
   ....
}
Run Code Online (Sandbox Code Playgroud)

  • 嗨,spajce,基本上这就是我打算做的。但是我创建的标量函数名称不存在于存储过程名称下拉列表中(尽管我已在模型浏览器中添加标量函数)。如果它是存储过程,它会出现在 DDL 中,但如果它是表/标量函数,它不会出现在 DDL 中。因此,我很难按照我在第一篇文章中提到的方式调用我的标量函数。谢谢 (3认同)