一尘不染

实体框架存储过程表值参数

c#

我正在尝试调用一个接受表值参数的存储过程。我知道Entity
Framework尚不直接支持此功能,但是据我了解,您可以使用的ExecuteStoreQuery命令来实现ObjectContext。我有一个通用实体框架存储库,其中有以下ExecuteStoredProcedure方法:

public IEnumerable<T> ExecuteStoredProcedure<T>(string procedureName, params object[] parameters)
{
    StringBuilder command = new StringBuilder();
    command.Append("EXEC ");
    command.Append(procedureName);
    command.Append(" ");

    // Add a placeholder for each parameter passed in
    for (int i = 0; i < parameters.Length; i++)
    {
        if (i > 0)
            command.Append(",");

        command.Append("{" + i + "}");
    }

    return this.context.ExecuteStoreQuery<T>(command.ToString(), parameters);
}

命令字符串最终如下所示:

EXEC someStoredProcedureName {0},{1},{2},{3},{4},{5},{6},{7}

我试图在接受表值参数的存储过程中运行此方法,但它会中断。我在这里读到,参数必须是类型SqlParameter,而表值参数需要将其SqlDbType设置为Structured。所以我这样做了,并得到一个错误说明:

The table type parameter p6 must have a valid type name

因此,我将SqlParameter.TypeName设置为在数据库上创建的用户定义类型的名称,然后在运行查询时收到以下真正有用的错误:

Incorrect syntax near '0'.

如果我恢复到ADO.NET并执行数据读取器,则可以使查询运行,但是我希望可以使用数据上下文使它正常工作。

有没有办法使用传递表值参数ExecuteStoreQuery?另外,我实际上使用的是Entity Framework Code
First,并将强制转换DbContextObjectContext以获得ExecuteStoreQuery可用的方法。这是否有必要,或者我也可以针对DbContext


阅读 279

收藏
2020-05-19

共1个答案

一尘不染

更新

我在Nuget软件包上添加了对此的支持-https:
//github.com/Fodsuk/EntityFrameworkExtras#nuget
(EF4,EF5,EF6)

查看GitHub存储库以获取代码示例。


稍有疑问,但是对于尝试将用户定义的表传递到存储过程中的人来说,它仍然有用。在研究了Nick的示例和其他Stackoverflow帖子之后,我想到了:

class Program
{
    static void Main(string[] args)
    {
        var entities = new NewBusinessEntities();

        var dt = new DataTable();
        dt.Columns.Add("WarningCode");
        dt.Columns.Add("StatusID");
        dt.Columns.Add("DecisionID");
        dt.Columns.Add("Criticality");

        dt.Rows.Add("EO01", 9, 4, 0);
        dt.Rows.Add("EO00", 9, 4, 0);
        dt.Rows.Add("EO02", 9, 4, 0);

        var caseId = new SqlParameter("caseid", SqlDbType.Int);
        caseId.Value = 1;

        var userId = new SqlParameter("userid", SqlDbType.UniqueIdentifier);
        userId.Value = Guid.Parse("846454D9-DE72-4EF4-ABE2-16EC3710EA0F");

        var warnings = new SqlParameter("warnings", SqlDbType.Structured);
        warnings.Value= dt;
        warnings.TypeName = "dbo.udt_Warnings";

        entities.ExecuteStoredProcedure("usp_RaiseWarnings_rs", userId, warnings, caseId);
    }
}

public static class ObjectContextExt
{
    public static void ExecuteStoredProcedure(this ObjectContext context, string storedProcName, params object[] parameters)
    {
        string command = "EXEC " + storedProcName + " @caseid, @userid, @warnings";

        context.ExecuteStoreCommand(command, parameters);
    }
}

存储过程如下所示:

ALTER PROCEDURE [dbo].[usp_RaiseWarnings_rs]
    (@CaseID int, 
     @UserID uniqueidentifier = '846454D9-DE72-4EF4-ABE2-16EC3710EA0F', --Admin
     @Warnings dbo.udt_Warnings READONLY
)
AS

用户定义的表如下所示:

CREATE TYPE [dbo].[udt_Warnings] AS TABLE(
    [WarningCode] [nvarchar](5) NULL,
    [StatusID] [int] NULL,
    [DecisionID] [int] NULL,
    [Criticality] [int] NULL DEFAULT ((0))
)

我发现的约束包括:

  1. 传入的参数ExecuteStoreCommand必须与存储过程中的参数一致
  2. 您必须将每一列传递到用户定义的表中,即使它们具有默认值也是如此。所以看来我的UDT上没有IDENTITY(1,1)NOT NULL列
2020-05-19