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

时间:2013-01-16 21:49:04

标签: c# entity-framework-4 user-defined-functions

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

但是,当我想将其添加到模型浏览器中的Function Imports文件夹时,下拉列表中会显示消息标量函数。有人能帮助我吗?

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

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

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

dbContext.ExecuteFunction("getMinActualLoadDate ", paramList);

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

感谢。

5 个答案:

答案 0 :(得分:12)

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

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

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

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

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

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

<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>

此信息可在此blog post

中找到

答案 1 :(得分:6)

这是我对这个问题的解决方案,这几乎正是你的经理所要求的......尽管已经晚了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();

    }

}

作为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();

        }

    }

}

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

答案 2 :(得分:1)

我猜您错过了Edit Function Import对话框,您可以在其中生成复杂类型。试着探索。

enter image description here

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

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

答案 3 :(得分:1)

唯一的解决方案是使用表中的单个值将函数标量类型转换为表值类型,请参阅代码示例。

您不必更改EDMX XML中的任何内容,请修改SQL函数

  

标量函数原样,它不起作用

CREATE FUNCTION [dbo].[GetSha256]
(
    -- Add the parameters for the function here
    @str nvarchar(max)
)
RETURNS VARBINARY(32)
AS
BEGIN
    RETURN ( SELECT * FROM HASHBYTES('SHA2_256', @str) AS HASH256 );
END -- this doesn't work.
  

标量函数 - &gt;转换为表值函数,它可以工作

CREATE FUNCTION [dbo].[GetSha2561]
(
    -- Add the parameters for the function here
    @str nvarchar(max)
)
RETURNS  @returnList TABLE (CODE varbinary(32))
AS
BEGIN

    INSERT INTO @returnList
    SELECT HASHBYTES('SHA2_256', @str);

    RETURN; -- This one works like a charm.

END

Edmx截图

enter image description here

答案 4 :(得分:0)

页面中的代码:

import { ActivatedRoute } from '@angular/router';

...

constructor(private activatedRoute: ActivatedRoute) {}

ngOnInit() {
    this.route.params.subscribe(params => {  
      // Do Something with the params you receive
      let id = params.get('id');
    }
}

标量函数:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        using (MayEntities context = new MayEntities())
        {
            string str = context.Database.SqlQuery<string>("select dbo.HeyYou()").Single().ToString();
            Response.Write(str); //output:'Hey this works'
        }
    }
}