VB.NET调用SQL Server存储过程传多参数查询日期间数据无结果
VB.NET调用SQL Server存储过程传筛选参数无返回数据修复方案
核心问题点
- 异常被完全吞服,无法定位真实错误:现有Catch块直接将DataSet赋值为Nothing,无任何错误日志,所有执行报错都会被前端识别为「无数据」,无法区分是真无匹配数据还是代码执行出错。
AddWithValue隐式类型推断导致参数类型不匹配(根因):所有参数通过AddWithValue传入时未显式指定SQL类型、长度:- 方法入参中日期为String类型,直接传给存储过程的datetime类型参数易出现格式解析偏差
- 纯数字格式的字符串参数会被
AddWithValue自动推断为int类型,和存储过程定义的nvarchar(60)类型不匹配,查询时发生隐式类型转换,要么直接报错(被吞掉),要么无法匹配到nvarchar类型存储的字段值。这也是SSMS直接传参能查到、程序传参查不到的核心原因——SSMS传入的字符串常量默认是nvarchar类型,和字段类型一致。
- 存储过程WHERE条件存在歧义:
RegistrationNo = ISNULL(@regNo, cv.RegistrationNo)未给字段加表别名,关联表存在同名字段时会出现解析错误;同时LEFT JOIN后直接在WHERE中写关联表的等值判断,部分场景会将LEFT JOIN强制转为INNER JOIN,过滤掉关联无结果的记录。 - 参数判断逻辑重复:存储过程和代码端未统一空值/默认值(比如参数为'0'时设为NULL)的判断规则,易出现逻辑不一致。
修复后代码
VB.NET 端代码
Public Shared Function SearchRoboCallByDate(datefrom As DateTime, dateto As DateTime, customerNo As String, regNo As String, terminalNo As String) As DataSet Dim ds As New DataSet() ' Using语法自动释放数据库连接、命令对象资源,避免资源泄漏 Using conn As New SqlConnection(ConfigurationManager.ConnectionStrings("SQLConnString").ConnectionString) Using cmd As New SqlCommand("sp_getRoboAlarmDetailByDate", conn) cmd.CommandType = CommandType.StoredProcedure cmd.CommandTimeout = 600 ' 显式指定每个参数的类型、长度,完全弃用AddWithValue避免隐式类型问题 cmd.Parameters.Add("@datefrom", SqlDbType.DateTime).Value = datefrom cmd.Parameters.Add("@dateto", SqlDbType.DateTime).Value = dateto ' 统一在代码端处理空值、默认值"0"的逻辑,和存储过程职责拆分 Dim pCustomerNo As SqlParameter = cmd.Parameters.Add("@customerNo", SqlDbType.NVarChar, 60) pCustomerNo.Value = If(String.IsNullOrWhiteSpace(customerNo) OrElse customerNo.Trim() = "0", DBNull.Value, customerNo.Trim()) Dim pRegNo As SqlParameter = cmd.Parameters.Add("@regNo", SqlDbType.NVarChar, 60) pRegNo.Value = If(String.IsNullOrWhiteSpace(regNo) OrElse regNo.Trim() = "0", DBNull.Value, regNo.Trim()) Dim pTerminalNo As SqlParameter = cmd.Parameters.Add("@TerminalNo", SqlDbType.NVarChar, 60) pTerminalNo.Value = If(String.IsNullOrWhiteSpace(terminalNo) OrElse terminalNo.Trim() = "0", DBNull.Value, terminalNo.Trim()) Dim adapter As New SqlDataAdapter(cmd) Try adapter.Fill(ds) Catch ex As Exception ' 生产环境必须在这里加错误日志记录ex的完整信息,禁止直接吞异常 ds = Nothing Throw ' 开发阶段直接抛出错误方便定位问题 End Try End Using End Using Return ds End Function
SQL Server 存储过程代码
ALTER PROCEDURE sp_getRoboAlarmDetailByDate @datefrom datetime = NULL, @dateto datetime = NULL, @customerNo as nvarchar(60) = NULL, @regNo as nvarchar(60) = NULL, @TerminalNo as nvarchar(60) = NULL AS BEGIN SET NOCOUNT ON; -- 关闭影响行数返回,减少网络传输开销 SELECT ID = 0, rda.RCLogID, rda.VehicleID, cv.RegistrationNo, rda.TerminalNo, rda.PollID, rda.PacketNo, rda.TableNo, rda.ServerID, rda.ServerName, rda.isCallSuccessful, rda.Remarks, rda.CreatedOn, c.CustomerID, c.CustomerNo FROM RoboCalls_DefuseAlarms_Log rda LEFT JOIN CustomersVehicles cv ON cv.VehicleId = rda.VehicleID LEFT JOIN Customers c ON c.CustomerID = cv.CustomerId WHERE rda.CreatedOn BETWEEN @datefrom AND @dateto -- 所有字段加表别名避免歧义,用参数空值判断写法替代ISNULL,更利于索引命中 AND (@customerNo IS NULL OR c.CustomerNo = @customerNo) AND (@regNo IS NULL OR cv.RegistrationNo = @regNo) AND (@TerminalNo IS NULL OR rda.TerminalNo = @TerminalNo) END
注意事项
- 方法入口的日期参数必须改为DateTime类型,不要用String接收日期,从源头避免不同服务器区域格式导致的日期解析错误
- 传入字符串参数前统一做Trim处理,避免前端传入的前后空格导致字段匹配失败
- 禁止在数据访问层直接吞掉所有异常,必须保留错误日志,否则后续出现问题完全无法定位
内容的提问来源于stack exchange,提问作者Sanaullah Shahbaz
相关产品推荐
相关产品推荐

