SQL Server将SP_EXECUTESQL识别为对象而不是过程名称

Dhw*_*ani 10 c# sql-server asp.net-mvc stored-procedures entity-framework

DBContext.Database.SqlQuery<entity>用来从我的C#代码库执行存储过程.

它工作正常,但我想知道它为什么执行如下程序:

exec sp_executesql N'EXEC GetCaseList @CaseStage',N'@CaseStage int',@CaseStage=9
Run Code Online (Sandbox Code Playgroud)

而不是

EXEC GetCaseList @CaseStage = 9
Run Code Online (Sandbox Code Playgroud)

有没有什么方法可以让我的所有程序从c#执行
EXEC GetCaseList @CaseStage = 9而不是exec sp_executesql N'EXEC GetCaseList @CaseStage',N'@CaseStage int',@CaseStage=9

如何使SQL Server Profiler将过程名称视为对象而不是SP_EXECUTESQL?

注意:我想从c#执行过程,EXEC GetCaseList @CaseStage = 9因为我通过SQL Server Profiler以表格格式保存跟踪数据.在ObjectName列中,它将sp_executesql显示为对象而不是过程名称(GetCaseList)作为对象.我只能从c#代码进行更改.

Iva*_*oev 6

问题是,大多数EF的进行数据库调用使用DbCommand带,所以虽然SqlServer的识别SP调用,它执行它们作为通过文本.CommadType Textsp_executesql

要获得所需的行为,应该以这种方式设置命令:

DbCommand command = ...;
command.CommandText = "StoredProcedureName";
command.CommandType = CommadType.StoredProcedure;
Run Code Online (Sandbox Code Playgroud)

不幸的是,EF没有提供指定命令类型的标准方法.我建议的解决方案基于:

  • 自定义SP调用SQL语法使用CallPrefix StoredProcedureName,以免干扰常规调用
  • EF命令拦截在执行命令之前删除前缀并更改命令类型.

这是实施:

using System.Data;
using System.Data.Common;
using System.Data.Entity.Infrastructure.Interception;

public static class Sp
{
    public const string CallPrefix = "CallSP ";

    public static string Call(string name) { return CallPrefix + name; }

    public class CallInterceptor : DbCommandInterceptor
    {
        public static void Install()
        {
            DbInterception.Remove(Instance);
            DbInterception.Add(Instance);
        }

        public static readonly CallInterceptor Instance = new CallInterceptor();

        private CallInterceptor() { }

        static void Process(DbCommand command)
        {
            if (command.CommandType == CommandType.Text && command.CommandText.StartsWith(Sp.CallPrefix))
            {
                command.CommandText = command.CommandText.Substring(Sp.CallPrefix.Length);
                command.CommandType = CommandType.StoredProcedure;
            }
        }

        public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
            Process(command);
            base.ReaderExecuting(command, interceptionContext);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您只需要将上面的类添加到项目中,调用Sp.CallInterceptor.Install()一次,例如在DbContext静态构造函数中:

public class YourDbContext : DbContext
{
    static YourDbContext()
    {
        Sp.CallInterceptor.Install();
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

然后像这样更改你的SP调用(使用你的样本):

从:

return DataContext.Database.SqlQuery<CaseList>("EXEC GetCaseList @CaseStage", 
    new SqlParameter("@CaseStage", paramList.CaseStageID)).ToList();
Run Code Online (Sandbox Code Playgroud)

至:

return DataContext.Database.SqlQuery<CaseList>(Sp.Call("GetCaseList"), 
    new SqlParameter("@CaseStage", paramList.CaseStageID)).ToList();
Run Code Online (Sandbox Code Playgroud)

这将生成(for paramList.CaseStageID == 9):

EXEC GetCaseList @CaseStage = 9
Run Code Online (Sandbox Code Playgroud)