[英]How to execute stored procedure with input and output parameters using EF?
I am using EF code first approach and I have created stored procedure using migration as following:我正在使用 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");
}
Now If I go to sql server management studio and execute the following scripts:现在如果我去 sql server management studio 并执行以下脚本:
Declare @Ids dbo.IdsList
Insert into @Ids
SELECT 1
Exec getChildIds @Ids
It will execute successfuly, but Now I am trying to execute that stored procedure as following:它将成功执行,但现在我正在尝试执行该存储过程,如下所示:
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;
It does not return anything.它不返回任何东西。
So how I could execute stored procedure with input and output parameters of type Table?那么如何使用 Table 类型的输入和输出参数来执行存储过程呢?
You will have to obtain your data a different way:您必须以不同的方式获取数据:
You cannot return data in a table-valued parameter. 您不能在表值参数中返回数据。 Table-valued parameters are input-only; 表值参数仅供输入; the OUTPUT keyword is not supported. 不支持 OUTPUT 关键字。
I have solved it this way.我是这样解决的。
First of all I have updated my stored procedure to return Ids as following:首先,我更新了我的存储过程以返回 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
");
}
And here how I have solved executing stored procedure using 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<int>("exec getChildIds @idsList", idsList).ToList();
I hope my code will help others having the same issue我希望我的代码能帮助其他有同样问题的人
The best solution for using user's procedures/functions and build-in functions in SQL is this library - https://github.com/Dixin/EntityFramework.Functions在 SQL 中使用用户过程/函数和内置函数的最佳解决方案是这个库 - https://github.com/Dixin/EntityFramework.Functions
It has great and easy implementation.它具有出色且易于实施的功能。 Also it allows to follow code first approach它还允许遵循代码优先的方法
In your case you need to use Table-valued function在您的情况下,您需要使用表值函数
Define model定义模型
[ComplexType]
public class IdModel
{
public int Id { get; set; }
}
Declare Type and Convention in DbContext在 DbContext 中声明类型和约定
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add(new FunctionConvention<DbContext>());
modelBuilder.ComplexType<IdModel>();
base.OnModelCreating(modelBuilder);
}
Define function in DbContext在 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);
}
And use it from your DbContext并从您的 DbContext 使用它
[TestMethod]
public void CallTableValuedFunction()
{
using (DbContext database = new DbContext())
{
IQueryable<IdModel> employees = database.ufnGetChildIds(new List<IdModel> { new IdModel { Id = 1 }});
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.