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

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

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) --Where Id=108 UNION ALL SELECT t.Id FROM dbo.PhysicalObjects t INNER JOIN RecursiveCTE cte ON t.ParentId = cte.Id ) SELECT * FROM RecursiveCTE End"); } public override void Down() { Sql(@"Drop Type IdsList Go Drop Procedure getChildIds"); } 

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

 Declare @Ids dbo.IdsList Insert into @Ids SELECT 1 Exec getChildIds @Ids 

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

  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("getChildIds @idsList, @idParams out", idsList,idParams) ; var idsResult = (List)idParams.Value; 

它没有返回任何东西。

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

您必须以不同的方式获取数据:

您不能在表值参数中返回数据。 表值参数仅为输入; 不支持OUTPUT关键字。

我这样解决了。

首先,我更新了我的存储过程以返回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 "); } 

在这里我是如何使用entity framework解决执行存储过程的:

  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("exec getChildIds @idsList", idsList).ToList(); 

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

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

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

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

定义模型

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

在DbContext中声明Type和Convention

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Add(new FunctionConvention()); modelBuilder.ComplexType(); base.OnModelCreating(modelBuilder); } 

在DbContext中定义函数

 [Function(FunctionType.TableValuedFunction, nameof(ufnGetChildIds), Schema = "dbo")] public IQueryable ufnGetChildIds([Parameter(DbType = "IdModel", Name = "IdsList")]List IdsList) { ObjectParameter IdsListParameter = new ObjectParameter("IdsList", IdsList); return this.ObjectContext().CreateQuery( $"[{nameof(this.ufnGetChildIds)}](@{nameof(IdsList)})", IdsListParameter); } 

并从你的DbContext中使用它

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