从存储过程中获取返回值
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函数,然后从上下文中调用它。
了解更多信息
对于使用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;
}
以上是关于从存储过程中获取返回值的主要内容,如果未能解决你的问题,请参考以下文章