Ответ 1
Проблема заключается в том, что в большинстве вызовов, вызванных EF, используются DbCommand
с CommadType
Text
, поэтому, хотя SqlServer распознает вызовы SP, он выполняет их как текст через sp_executesql
.
Чтобы получить желаемое поведение, команда должна быть настроена следующим образом:
DbCommand command = ...;
command.CommandText = "StoredProcedureName";
command.CommandType = CommadType.StoredProcedure;
К сожалению, EF не предоставляет стандартный способ указания типа команды. Решение, которое я предлагаю, основано на:
- Пользовательский синтаксис SQL вызова SQL с использованием
CallPrefix StoredProcedureName
, чтобы не мешать регулярным вызовам - EF command interception, чтобы удалить префикс и изменить тип команды перед выполнением команды.
Вот реализация:
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);
}
}
}
Все, что вам нужно, - добавить вышеописанный класс к вашему проекту, вызвать Sp.CallInterceptor.Install()
один раз, например, внутри статического конструктора DbContext
:
public class YourDbContext : DbContext
{
static YourDbContext()
{
Sp.CallInterceptor.Install();
}
// ...
}
а затем измените ваши вызовы SP, как это (используя ваш образец):
от
return DataContext.Database.SqlQuery<CaseList>("EXEC GetCaseList @CaseStage",
new SqlParameter("@CaseStage", paramList.CaseStageID)).ToList();
в
return DataContext.Database.SqlQuery<CaseList>(Sp.Call("GetCaseList"),
new SqlParameter("@CaseStage", paramList.CaseStageID)).ToList();
который будет генерировать (для paramList.CaseStageID == 9
):
EXEC GetCaseList @CaseStage = 9