如何使用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 }}); } }