【问题标题】:How to get return values and output values from a stored procedure with EF Core?如何使用 EF Core 从存储过程中获取返回值和输出值?
【发布时间】:2017-10-11 15:11:07
【问题描述】:
ALTER PROCEDURE [dbo].[SearchMovies]
    --@Year     int = null,
    @CategoryIds varchar(50) = null,
    @Keywords nvarchar(4000) = null,
    @PageIndex int = 1, 
    @PageSize int = 2147483644,
    @TotalRecords int = null OUTPUT
As ...

EF 存储库:

 public class EFRepository<T> : IRepository<T> where T : BaseEntity
{
    private readonly ApplicationDbContext _ctx;
    private  DbSet<T> entities;
    string errorMessage = string.Empty;

    public EFRepository(ApplicationDbContext context)
    {
        this._ctx = context;
        entities = context.Set<T>();
    }     
   ...

    public IQueryable<T> ExecuteStoredProcedureList(string commandText, params object[] parameters)
    {          
        _ctx.Database.ExecuteSqlCommand(commandText, parameters);
        return entities.FromSql(commandText, parameters);
    }
}

我这样称呼它:

var pCategoryIds = new SqlParameter()
            {
                ParameterName = "@CategoryIds",
                Value = commaSeparatedCategoryIds,
                DbType = DbType.String
            };
var pKeywords = new SqlParameter()
            {
                ParameterName = "@Keywords",
                DbType = DbType.String,
                Value = name
            };
var pPageIndex = new SqlParameter()
            {
                ParameterName = "@PageIndex",
                DbType = DbType.Int32,
                Value = pageIndex
            };
var pPageSize = new SqlParameter()
            {
                ParameterName = "@PageSize",
                DbType = DbType.Int32,
                Value = pageSize
            };

var pTotalRecords = new SqlParameter();
pTotalRecords.ParameterName = "@TotalRecords";
pTotalRecords.Direction = ParameterDirection.Output;
pTotalRecords.DbType = DbType.Int32;

var query1 = _ctx.Database.ExecuteSqlCommand("dbo.[SearchMovies] " +
                "@CategoryIds, @Keywords, @PageIndex, @PageSize, @TotalRecords OUTPUT", 
                pCategoryIds, pKeywords, pPageIndex, pPageSize, pTotalRecords);

var query2 = _ctx.Set<MovieItem>.FromSql("dbo.[SearchMovies] " +
                    "@CategoryIds, @Keywords, @PageIndex, @PageSize, @TotalRecords OUTPUT",
                    pCategoryIds, pKeywords, pPageIndex, pPageSize, pTotalRecords);

query1 确实得到了输出pTotalRecords,但没有返回值,第二个query2 得到返回值但没有输出参数。

在 EF 6 中,我们曾经有 SqlQuery 在一个命令中执行这两个操作,我如何在 EF 核心中执行相同的操作?

更新

我暂时运行了 2 个查询,一个用于获取输出参数,一个用于结果集。

 public IQueryable<T> ExecuteStoredProcedureList(string commandText, params object[] parameters)
    {          
        _ctx.Database.ExecuteSqlCommand(commandText, parameters);
        return entities.FromSql(commandText, parameters);
    }

【问题讨论】:

  • 您的 MovieItem 型号是什么?它是否具有与存储过程返回的完全相同的属性?
  • 所以你的意思是使用 Fromsql 它可以返回输出参数? ExecuteSqlCommand 将返回一个整数,在存储过程中,SELECT m.* ... from dbo.MovieItem m 这与 MovieItem 实体完全相同。
  • 从 EF Core 1.x 开始,EF Core 仅支持映射到现有实体的结果值,并且该实体中不能缺少任何字段。请参阅EF Core roadmap非模型类型的原始 SQL 查询允许使用原始 SQL 查询来填充不属于模型的类型(通常用于非规范化视图模型数据)。
  • 我没有问题得到上面所说的结果,使用 FromSql 我得到了所有结果,除了 TotalRecords 这是一个行数。而且似乎 EF 核心仍然缺少此功能,因为我已经搜索了几个小时,但没有人为此提供示例。见dotnetthoughts.net/how-to-execute-storedprocedure-in-ef-core
  • @DmitryPavlov 感谢您的信息。好像是这里提到的github.com/aspnet/EntityFrameworkCore/issues/9309 2.0.3 版本的补丁,2.0.3 还没有出来。

标签: c# asp.net-mvc entity-framework asp.net-core entity-framework-core


【解决方案1】:

我做了这样的事情:-

-- 我的存储过程:

CREATE PROCEDURE p1
AS
     BEGIN            
        RETURN 29
     END
GO

C#代码

SqlParameter[] @params = 
{
   new SqlParameter("@returnVal", SqlDbType.Int) {Direction = ParameterDirection.Output}
 };   


_stagingContext.Database.ExecuteSqlCommand("exec @returnVal=" + storedProcName, @params);

var result = @params[0].Value; //result is 29 

希望对你有帮助

【讨论】:

  • 谢谢。我需要对数据库进行简单的 GetDate() 调用,这在 EF Core 中并不容易。这暂时解决了它。
  • 我的问题是如何返回数据集和输出值,而不仅仅是输出变量
  • 您能否解释一下,为什么选择 ParameterDirection.Output 而不是 ParameterDirection.ReturnValue? p1 将 29 作为“简单”返回值返回,而不是作为输出参数。
【解决方案2】:

我正在努力将一些 EF6 代码转换为 EF Core,并遇到了同样的问题。在 Microsoft.EntityFrameworkCore 版本 2.1.0 中,FromSql() 的以下使用确实返回结果集并设置输出参数。您必须使用.ToList() 强制 proc 立即执行,从而返回结果和输出参数。

这是来自我的 DbContext 类的示例:

private DbQuery<ExampleStoredProc_Result> ExampleStoredProc_Results { get; set; }
public IEnumerable<ExampleStoredProc_Result> RunExampleStoredProc(int firstId, out bool outputBit)
{
    var outputBitParameter = new SqlParameter
    {
        ParameterName = "outputBit",
        SqlDbType = SqlDbType.Bit,
        Direction = ParameterDirection.Output
    };

    SqlParameter[] parameters =
    {
        new SqlParameter("firstId", firstId),
        outputBitParameter
    };

    // Need to do a ToList to get the query to execute immediately 
    // so that we can get both the results and the output parameter.
    string sqlQuery = "Exec [ExampleStoredProc] @firstId, @outputBit OUTPUT";
    var results = ExampleStoredProc_Results.FromSql(sqlQuery, parameters).ToList();

    outputBit = outputBitParameter.Value as bool? ?? default(bool);

    return results;
}

存储过程返回以下实体:

public class ExampleStoredProc_Result
{
    public int ID { get; set; }
    public string Name { get; set; }
}

这是存储过程:

CREATE PROCEDURE ExampleStoredProc 
    @firstId int = 0,
    @outputBit BIT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    SET @outputBit = 1;

    SELECT @firstId AS [ID], 'first' AS [NAME]
    UNION ALL
    SELECT @firstId + 1 AS [ID], 'second' AS [NAME]
END
GO

希望以后看到这篇文章的人会觉得这很有用。

【讨论】:

    【解决方案3】:
    var results = ExampleStoredProc_Results.FromSql(sqlQuery, parameters).ToList();
    

    DbSet.FromSql 使您能够传入要对数据库执行的 SQL 命令,以返回由 DbSet 表示的类型的实例。

    这个答案对我有用。

    【讨论】:

    • FromSql 效率不高,因为映射表中的所有列都会被返回。
    【解决方案4】:

    在尝试使用 ExecuteSqlCommandAsync EF Core 调用具有一个输入和一个输出参数的存储过程时。我避免在实体对象上使用 FromSql。下面的代码对我来说效果很好,所以只想在这个旧帖子上分享。

        SqlParameter Param1 = new SqlParameter();
        Param1 .ParameterName = "@Param1";
        Param1 .SqlDbType = SqlDbType.VarChar;
        Param1 .Direction = ParameterDirection.Input;
        Param1 .Size = 50;
        Param1 .Value = "ParamValue";
    
        SqlParameter Param2 = new SqlParameter();
        Param2 .ParameterName = "@Param2";
        Param2 .SqlDbType = SqlDbType.VarChar;
        Param2 .Size = 2048;
        Param2 .Direction = ParameterDirection.Output;
    
        var sprocResponse = await _dbContext.Database.ExecuteSqlCommandAsync("[dbo].[StoredProcName]  @Param1= @Param1, @Param2 = @Param2 OUTPUT", new object[] { Param1, Param2});
        string outPutVal= urlParam.Value.ToString();
    

    【讨论】:

      猜你喜欢
      • 2017-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-22
      相关资源
      最近更新 更多