如何在 ASP.NET Core MVC 中使用 ADO.NET 向存储过程添加参数?
Posted
技术标签:
【中文标题】如何在 ASP.NET Core MVC 中使用 ADO.NET 向存储过程添加参数?【英文标题】:How can I add parameters to a stored procedure using ADO.NET in ASP.NET Core MVC? 【发布时间】:2021-05-03 17:52:00 【问题描述】:我想在 ASP.NET Core MVC 中执行具有 ADO.NET 输出参数的存储过程。但是我收到一条错误消息,说我的存储过程需要一个我已经设置的参数。
我的存储过程是这样的:
ALTER PROCEDURE [dbo].[spSearch]
@Notes nvarchar(max) = NULL,
@StartDate datetime = NULL,
@EndDate datetime = NULL,
@UserId nvarchar(450),
@Result money OUTPUT
AS
BEGIN
IF (@StartDate > @EndDate)
BEGIN
RAISERROR (N'Start date cannot be greater than end date',16,1)
END
ELSE
BEGIN
IF (@Notes IS NULL OR @Notes = '')
BEGIN
SELECT *
FROM Expenses
WHERE UserId = @UserId
AND [date] BETWEEN @StartDate AND @EndDate
ORDER BY [date] DESC
IF (@@ROWCOUNT = 0)
BEGIN
RAISERROR (N'No data found according to date match', 16, 1)
END
SELECT @Result = SUM(amount)
FROM Expenses
WHERE UserId = @UserId
AND [date] BETWEEN @StartDate AND @EndDate
END
ELSE
BEGIN
IF (@StartDate IS NULL OR @StartDate = '' OR @EndDate IS NULL OR @EndDate = '')
BEGIN
SELECT *
FROM expenses
WHERE UserId = @UserId
AND Notes LIKE '%' + @notes + '%'
ORDER BY [date] DESC
SELECT @Result = SUM(amount)
FROM expenses
WHERE UserId = @UserId
AND notes IN (SELECT notes
FROM expenses
WHERE notes LIKE '%' + @Notes + '%')
END
ELSE
BEGIN
SELECT *
FROM Expenses
WHERE UserId=@UserId and notes LIKE '%' + @notes + '%' and [date] BETWEEN @StartDate AND @EndDate
ORDER BY [date] DESC
IF( @@ROWCOUNT = 0 )
BEGIN
RAISERROR(N'No matching record found',16,1)
END
SELECT @Result = Sum(amount)
FROM Expenses
WHERE Notes IN(SELECT Notes
FROM Expenses
WHERE UserId=@UserId and notes LIKE '%' + @Notes + '%')
AND [date] BETWEEN @StartDate AND @EndDate
END
END
END
END
我的方法是这样的:
public IQueryable<Expenses> SearchExpenses(string UserId, string Notes, DateTime startFrom, DateTime endTo)
List<Expenses> expenses = new List<Expenses>();
using (DALC.GetConnection())
DALC.Command("[spSearch]");
DALC.cmd.Parameters.Add("@Notes", SqlDbType.NVarChar).Value = Notes;
DALC.cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = startFrom;
DALC.cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = endTo;
DALC.cmd.Parameters.Add("@UserId", SqlDbType.NVarChar).Value = UserId;//I set my sp paremeter here but why error?
//Is This the correct way to set an output parameter?
SqlParameter howMuch = new SqlParameter("@Result", SqlDbType.Money);
howMuch.Direction = ParameterDirection.Output;
DALC.cmd.Parameters.Add(howMuch);
DALC.cmd.ExecuteNonQuery();
var result = Convert.ToDecimal(DALC.cmd.Parameters["@Result"]);
using (SqlDataReader reader = DALC.cmd.ExecuteReader())
reader.Read();
Expenses expense = new Expenses
Id = Convert.ToInt32(reader["Id"]),
Desription = reader["Notes"].ToString(),
Date = Convert.ToDateTime(reader["Date"]),
IsCash = Convert.ToBoolean(reader["IsCash"]),
IsCard = Convert.ToBoolean(reader["IsCash"]),
SearchResultOut = result
;
expenses.Add(expense);
return expenses.AsQueryable();
错误:
System.Data.SqlClient.SqlException: '过程或函数'spSearch' 需要未提供的参数“@UserId”。
还有我的控制器:
[HttpPost]
public IActionResult Search(string UserId, string notes, DateTime startFrom, DateTime endTo)
UserId = GetUserId();
context.SearchExpenses(UserId,notes,startFrom,endTo);
return View();
【问题讨论】:
你能出示你的 DALC 吗? 您是否将CommandType 设置为StoredProcedure
?
@Sergey 是的,但是这不是我第一次使用这个class.. 到目前为止还没有问题..
@Zer0 肯定接受a look..
【参考方案1】:
考虑以同样的方式创建所有的 sql 参数。
对于输出参数,您通过创建一个sql参数对象并设置方向来正确地做到这一点。
你应该尝试对其他参数做同样的事情(当然不要设置方向)
调试
你应该在执行之前放置一个断点,并在 cmd 对象的参数集合中添加一个监视以查看它的样子。
还要验证 cmd 对象是否属于存储过程类型。
如果全部检查完毕,打开 sql profiler,您应该能够看到通过 SQL profiler 传入的内容,并获取对存储过程及其所有参数的实际调用。
进行实际调用并在 SSMS 上运行,看看它做了什么。
这应该可以帮助您弄清楚。
当你得到结果时,语法是 var 结果 = Convert.ToDecimal(DALC.cmd.Parameters["@Result"].Value);
【讨论】:
是的,当有疑问时,我几乎总是检查数据库正在获取的确切命令。 SQL Profiler 在发现客户端难以调试的问题时非常有用。只需查看数据库正在尝试执行的生成的 SQL 语句,就可以节省大量时间。 是的。似乎多年来把一个人的头撞在众所周知的墙上有一些好处。 @Chuma 是的,我在发布这个问题之前已经完成了。This 是控制器断点,this 是我的手表 @Chuma 有人提到 cmd 对象是dalc class中的一个sp 您的 DALC 类似乎只是实例化、返回并允许执行标准命令对象。那么一步一步来,你有没有放过手表并验证了命令对象的设置及其参数集合?我在手表中看到的似乎是传递给函数的参数,而不是命令对象在执行之前的参数。探查器还显示什么?【参考方案2】:在你的“DALC”类中的“Command”方法不能正常工作。 因为“命令”值在第一个字母中有特殊字符。
var commandwithspecialCharacter = "[spSearch]";
var cmd = new SqlCommand(commandwithspecialCharacter, new SqlConnection());
if (commandwithspecialCharacter.StartsWith("sp"))
cmd.CommandType = System.Data.CommandType.StoredProcedure;
Console.WriteLine($"commandwithspecialCharacter==>cmd.CommandType");
第一个输出commandwithspecialCharachter==>文本
var commandwithoutspecialCharacter = "spSearch";
if (commandwithoutspecialCharacter.StartsWith("sp"))
cmd.CommandType = System.Data.CommandType.StoredProcedure;
Console.WriteLine($"commandwithoutspecialCharacter==>cmd.CommandType");
第二个输出commandwithoutspecialCharacter==>StoredProcedure
在startsWith方法中,结果为假,因为它有“[”字符。 StartsWith 控件与“Command”方法中的“[sp”控件一起正常工作。
【讨论】:
以上是关于如何在 ASP.NET Core MVC 中使用 ADO.NET 向存储过程添加参数?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 ASP.NET Core MVC 中使用依赖注入设计存储库模式?
如何在 ASP.NET Core MVC 中使用 ADO.NET 向存储过程添加参数?
如何使用 C# 在 ASP.NET Core 3.1 MVC 中使用会话变量
如何在 ASP.Net Core MVC 中使用 HTML 链接?