从存储过程中获取返回值

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从存储过程中获取返回值相关的知识,希望对你有一定的参考价值。

我正在使用Entity Framework 5和Code First方法。我需要从存储过程中读取返回值;我已经在读取输出参数和发送输入参数,但我不知道如何读取返回值。

可能吗?

这是我用来调用存储过程的代码:

var outParam = new SqlParameter();
outParam.ParameterName = "@StatusLog";
outParam.SqlDbType = SqlDbType.NVarChar;
outParam.Size = 4000;
outParam.Direction = ParameterDirection.Output;

var code = new SqlParameter();
code.ParameterName = "@Code";
code.Direction = ParameterDirection.Input;
code.SqlDbType = SqlDbType.VarChar;
code.Size = 20;
code.Value = "123";

var data = _context.Database.SqlQuery<Item>("exec spItemData @Code, @StatusLog OUT", code, outParam);

var result = data.FirstOrDefault();
答案

我找到了!我可以使用必须以这种方式使用的输出参数来读取返回值:

// define a new output parameter
var returnCode = new SqlParameter();
returnCode.ParameterName = "@ReturnCode";
returnCode.SqlDbType = SqlDbType.Int;
returnCode.Direction = ParameterDirection.Output;

// assign the return code to the new output parameter and pass it to the sp
var data = _context.Database.SqlQuery<Item>("exec @ReturnCode = spItemData @Code, @StatusLog OUT", returnCode, code, outParam);
另一答案

Daniele提供的解决方案对我不起作用,直到我从blog post找到这个Diego Vega,这解释了:

在访问输出参数的值之前,您需要阅读整个结果(...)这就是存储过程的工作方式,而不是特定于此EF功能。

另外,在我的情况下,我没有返回一个实体,我只需要执行存储过程,所以我用Item中的object替换_context.Database.SqlQuery<object>

以下是示例代码:

var code = new SqlParameter("@Code", 1);

var returnCode = new SqlParameter("@ReturnCode", SqlDbType.Int);
returnCode.Direction = ParameterDirection.Output;

var outParam = new SqlParameter("@StatusLog", SqlDbType.Int);
outParam.Direction = ParameterDirection.Output;

var sql = "exec @ReturnCode = spSomeRoutine @Code, @StatusLog OUT";
var data = _context.Database.SqlQuery<object>(sql, returnCode, code, outParam);

// Read the results so that the output variables are accessible
var item = data.FirstOrDefault();

var returnCodeValue = (int)returnCode.Value;
var outParamValue = (int)outParam.Value;

这是一个示例存储过程:

CREATE PROCEDURE [dbo].[spSomeRoutine]
    @Code Int,
    @StatusLog INT OUTPUT
AS
BEGIN
    SET @StatusLog = 5
    RETURN 10
END
另一答案

在存储过程没有输出参数的情况下,我执行以下操作,有效地使一些Sql返回一个select语句;

var data = context.Database.SqlQuery<int>(@"declare @num int
exec  @num = myStoredProcThatReturnsInt 
select @num");

var result = data.First();
另一答案

您可以将存储过程添加为EF函数,然后从上下文中调用它。

http://www.entityframeworktutorial.net/EntityFramework4.3/execute-stored-procedure-using-dbcontext.aspx

了解更多信息

另一答案

对于使用EDMX文件的任何人,您可以添加代码生成项,然后使用以下t4代码替换.Context.tt。它将使用以下方法创建映射存储过程的所有代码:

var returnCode = new SqlParameter("@ReturnCode", SqlDbType.Int);
returnCode.Direction = ParameterDirection.Output;
var sql = "exec @ReturnCode = spSomeRoutine @Code, @StatusLog OUT";
var data = _context.Database.SqlQuery<object>(sql, returnCode, code, outParam);

当有结果集时它将使用SqlQuery <>,而当没有结果集时将使用ExecuteSqlCommand,但在两种情况下,out SqlParameter localSqlExecReturnValue将包含来自存储过程调用的int返回码。这可以与其他生成器一起使用,它只为存储过程调用生成其他代码。

stored procedure.context.天天:

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF6.Utility.CS.ttinclude"#><#@
 output extension=".cs"#><#

const string inputFile = @"CDMSAccountingModel.edmx";
var textTransform = DynamicTextTransformation.Create(this);
var code = new CodeGenerationTools(this);
var ef = new MetadataTools(this);
var typeMapper = new TypeMapper(code, ef, textTransform.Errors);
var loader = new EdmMetadataLoader(textTransform.Host, textTransform.Errors);
var itemCollection = loader.CreateEdmItemCollection(inputFile);
var modelNamespace = loader.GetModelNamespace(inputFile);
var codeStringGenerator = new CodeStringGenerator(code, typeMapper, ef);

var container = itemCollection.OfType<EntityContainer>().FirstOrDefault();
if (container == null)
{
    return string.Empty;
}
#>
//------------------------------------------------------------------------------
// <auto-generated>
// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine1")#>
//
// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine2")#>
// <#=CodeGenerationTools.GetResourceString("Template_GeneratedCodeCommentLine3")#>
// </auto-generated>
//------------------------------------------------------------------------------

<#

var codeNamespace = code.VsNamespaceSuggestion();
if (!String.IsNullOrEmpty(codeNamespace))
{
#>
namespace <#=code.EscapeNamespace(codeNamespace)#>
{
<#
    PushIndent("    ");
}

#>
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
<#
if (container.FunctionImports.Any())
{
#>
using System.Data.Entity.Core.Objects;
using System.Linq;
<#
}
#>

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
{

<#
foreach (var entitySet in container.BaseEntitySets.OfType<EntitySet>())
{
    // Note: the DbSet members are defined below such that the getter and
    // setter always have the same accessibility as the DbSet definition
    if (Accessibility.ForReadOnlyProperty(entitySet) != "public")
    {
#>
        <#=codeStringGenerator.DbSetInitializer(entitySet)#>
<#
    }
}
#>



<#
    foreach (var edmFunction in container.FunctionImports)
    {
        WriteFunctionImport(typeMapper, codeStringGenerator, edmFunction, modelNamespace, includeMergeOption: false);
    }
#>
}
<#

if (!String.IsNullOrEmpty(codeNamespace))
{
    PopIndent();
#>
}
<#
}
#>
<#+

private void WriteFunctionImport(TypeMapper typeMapper, CodeStringGenerator codeStringGenerator, EdmFunction edmFunction, string modelNamespace, bool includeMergeOption)
{
    if (typeMapper.IsComposable(edmFunction))
    {
#>

    [DbFunction("<#=edmFunction.NamespaceName#>", "<#=edmFunction.Name#>")]
    <#=codeStringGenerator.ComposableFunctionMethod(edmFunction, modelNamespace)#>
    {
<#+
        codeStringGenerator.WriteFunctionParameters(edmFunction, WriteFunctionParameter );
#>
        <#=codeStringGenerator.ComposableCreateQuery(edmFunction, modelNamespace)#>
    }
<#+
    }
    else
    {
#>

    <#=codeStringGenerator.FunctionMethod(edmFunction, modelNamespace, includeMergeOption)#>
    {
<#+
        codeStringGenerator.WriteFunctionParameters(edmFunction, WriteFunctionParameter);
#>
        localSqlExecReturnValue = new System.Data.SqlClient.SqlParameter("@localExecReturnValue",System.Data.SqlDbType.Int);
        localSqlExecReturnValue.Direction = System.Data.ParameterDirection.Output;

        <#=codeStringGenerator.ExecuteFunction(edmFunction, modelNamespace, includeMergeOption)#>
    }
<#+
        if (typeMapper.GenerateMergeOptionFunction(edmFunction, includeMergeOption))
        {
            WriteFunctionImport(typeMapper, codeStringGenerator, edmFunction, modelNamespace, includeMergeOption: true);
        }
    }
}

public void WriteFunctionParameter(string name, string isNotNull, string notNullInit, string nullInit)
{
#>
        var <#=name#> = <#=isNotNull#> ?
            <#=notNullInit#> :
            <#=nullInit#>;

<#+
}

public const string TemplateId = "CSharp_DbContext_Context_EF6";

public class CodeStringGenerator
{
    private readonly CodeGenerationTools _code;
    private readonly TypeMapper _typeMapper;
    private readonly MetadataTools _ef;

    public CodeStringGenerator(CodeGenerationTools code, TypeMapper typeMapper, MetadataTools ef)
    {
        ArgumentNotNull(code, "code");
        ArgumentNotNull(typeMapper, "typeMapper");
        ArgumentNotNull(ef, "ef");

        _code = code;
        _typeMapper = typeMapper;
        _ef = ef;
    }

 

以上是关于从存储过程中获取返回值的主要内容,如果未能解决你的问题,请参考以下文章

如何从 ASP.NET Core Web API 中的 SQL Server 存储过程中获取返回值

如何从 Oracle 存储过程中获取两个返回值

从 C# 中的存储过程中获取返回值

如何从实体框架中的存储过程中获取结果+数据库优先

从SQL存储过程获取返回值

从多列返回值的 SQL 函数