如何使用EF执行带输入和输出参数的存储过程?

时间:2018-02-19 12:25:12

标签: c# sql-server entity-framework stored-procedures

我正在使用EF代码第一种方法,我使用迁移创建了存储过程,如下所示:

Declare @Ids dbo.IdsList

Insert into @Ids
SELECT 1

Exec getChildIds @Ids

现在如果我去sql server management studio并执行以下脚本:

 var idsList = new SqlParameter {ParameterName = "idsList",  Value = new int[] { 1,2,3,4,5} };

 var idParams = new SqlParameter("idParams", SqlDbType.Structured)
            {
                Direction = System.Data.ParameterDirection.Output
            };

var results = dbContext.Database.SqlQuery<int>("getChildIds @idsList, @idParams out", idsList,idParams) ;

var idsResult = (List<int>)idParams.Value;

它将成功执行,但现在我尝试执行该存储过程如下:

Task

它不会返回任何内容。

那么我如何使用Table类型的输入和输出参数执行存储过程?

3 个答案:

答案 0 :(得分:1)

答案 1 :(得分:0)

我已经解决了这个问题。

首先,我更新了我的存储过程以返回ID,如下所示:

 public override void Up()
    {
        Sql(@"CREATE TYPE IdsList AS TABLE   
                    ( 
                    Id Int
                    )
                    GO

                    Create Procedure getChildIds(
                    @IdsList dbo.IdsList ReadOnly
                    )
                    As
                    Begin
                    WITH RecursiveCTE AS
                    (
                        SELECT Id
                        FROM dbo.PhysicalObjects
                        WHERE ParentId in (Select * from @IdsList)
                        UNION ALL

                        SELECT t.Id
                        FROM dbo.PhysicalObjects t
                        INNER JOIN RecursiveCTE cte ON t.ParentId = cte.Id
                    )
                    SELECT Id From RecursiveCTE
                    End");
    }

    public override void Down()
    {
        Sql(@" Drop Procedure getChildIds
               Go
               Drop Type IdsList
               ");
    }

这里我是如何使用实体框架解决执行存储过程的:

 var dataTable = new DataTable();
 dataTable.TableName = "idsList";
 dataTable.Columns.Add("Id", typeof(int));
 dataTable.Rows.Add(1);
 dataTable.Rows.Add(2);

  SqlParameter idsList = new SqlParameter("idsList", SqlDbType.Structured);
  idsList.TypeName = dataTable.TableName;
  idsList.Value = dataTable;

  var results = dbContext.Database.SqlQuery<int>("exec getChildIds @idsList", idsList).ToList();

我希望我的代码可以帮助其他人遇到同样的问题

答案 2 :(得分:0)

在SQL中使用用户程序/函数和内置函数的最佳解决方案是此库 - https://github.com/Dixin/EntityFramework.Functions

它实现起来非常简单。它还允许遵循代码第一种方法

在您的情况下,您需要使用表值函数

定义模型

[ComplexType]
public class IdModel
{
     public int Id { get; set; }
}

在DbContext中声明类型和约定

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Add(new FunctionConvention<DbContext>());

    modelBuilder.ComplexType<IdModel>();

    base.OnModelCreating(modelBuilder);
}

在DbContext中定义函数

[Function(FunctionType.TableValuedFunction, nameof(ufnGetChildIds), Schema = "dbo")]
public IQueryable<IdModel> ufnGetChildIds([Parameter(DbType = "IdModel", Name = "IdsList")]List<IdModel> IdsList)
{
    ObjectParameter IdsListParameter = new ObjectParameter("IdsList", IdsList);

    return this.ObjectContext().CreateQuery<IdModel>(
        $"[{nameof(this.ufnGetChildIds)}](@{nameof(IdsList)})", IdsListParameter);
}

从DbContext

中使用它
[TestMethod]
public void CallTableValuedFunction()
{
    using (DbContext database = new DbContext())
    {
        IQueryable<IdModel> employees = database.ufnGetChildIds(new List<IdModel> { new IdModel { Id = 1 }});
    }
}