System.Data.SqlClient.SqlException:“将 nvarchar 值 'STORES' 转换为数据类型 int 时转换失败。”

Posted

技术标签:

【中文标题】System.Data.SqlClient.SqlException:“将 nvarchar 值 \'STORES\' 转换为数据类型 int 时转换失败。”【英文标题】:System.Data.SqlClient.SqlException: 'Conversion failed when converting the nvarchar value 'STORES' to data type int.'System.Data.SqlClient.SqlException:“将 nvarchar 值 'STORES' 转换为数据类型 int 时转换失败。” 【发布时间】:2021-06-05 15:42:03 【问题描述】:

我正在 C# asmx webservice 中执行存储过程。 存储过程如下:

@userName NVARCHAR(50),
@password NVARCHAR(50),
@defaultTabApp NVARCHAR(20) OUT
AS
Declare @defaultTabApptemp NVARCHAR(20)
set @defaultTabApptemp ='NoAccess'
BEGIN TRANSACTION
    if EXISTS(SELECT Top 1  [userId],[userName] FROM [dbo].[users] WHERE [userName]=@userName AND [password]=@password AND [AppAccess]=N'Yes') 
    Begin
       set @defaultTabApptemp = (select Top 1 [dbo].[users].[defaultTabApp] FROM [dbo].[users] WHERE [userName]=@userName AND [password]=@password AND [AppAccess]=N'Yes')
    end
 select @defaultTabApp =  @defaultTabApptemp 

COMMIT TRANSACTION
return @defaultTabApp

我的 C# 代码是:

[WebMethod]
        public string Login(string userName, string userPass)
        
            string result;
            SqlConnection conn = new SqlConnection(new DBConnection().ConnectionString);
           
            try
            

                SqlCommand cmd = new SqlCommand("_getSpecificUserLogin", conn);
                cmd.CommandType = System.Data.CommandType.StoredProcedure;
                
                if (conn.State == System.Data.ConnectionState.Closed)
                
                    conn.Open();
                
                
                cmd.Parameters.AddWithValue("@userName", userName);
                cmd.Parameters.AddWithValue("@password", userPass);
               

                cmd.Parameters.Add("@defaultTabApp", SqlDbType.NVarChar,20);
                cmd.Parameters["@defaultTabApp"].Direction = ParameterDirection.Output;
                int i = cmd.ExecuteNonQuery();
                result = Convert.ToString(cmd.Parameters["@defaultTabApp"].Value);

            


            finally
            
                conn.Close();
            
            return result;

我在这一行的标题中发现了异常:int i = cmd.ExecuteNonQuery(); 我试图将其更改为执行标量,但遇到了同样的问题。我的存储过程中没有 int 类型。究竟是什么问题?提前致谢。

【问题讨论】:

您的程序似乎有点混乱。您是否使用 SSMS 运行该程序并检查其输出是否正确?我不相信你有正确的语法,或者可以使用 RETURN 语句来达到你想要的目的。请提供表架构和示例数据。 而且不需要if exists...select...,你可以在一行中完成所有操作,然后你也不需要交易我希望你没有存储明文密码...... 其实我的同事写了存储过程,我应该写webservice的c#代码。所以最好不要使用return语句? 【参考方案1】:

您的登录过程的基本内容应如下所示。

请注意,您不需要事务,也不需要首先检查是否存在任何东西 - 这是因为它为您的输出变量分配了一个值。

您的代码无法处理密码不正确或没有为用户启用的应用程序的情况。

实际上,您会首先验证用户并为他们分配某种票证以表明他们已成功登录并且不会重复检查他们的密码;当需要获取他们的默认应用时,他们已经通过了身份验证。

如果您可以让一个用户拥有多个 appAccess='Yes',则您只需要前 1 个,在这种情况下,您将缺少用于选择正确用户的排序标准 - 没有特定的 order 子句,该值本质上是随机的。

输出参数的正确语法是Output

如果这是一个面向公众的应用程序,我也希望密码不是纯文本,而是作为用户密码的哈希值存储在数据库中。

create procedure UserLogin
@userName nvarchar(50),
@password nvarchar(50), -- This should be a HASH of the user's password, performed by the application
@defaultTabApp nvarchar(20) output
as
set nocount on
set @defaultTabApp='Default failure message'

select top 1 @defaultTabApp=defaultTabApp
from dbo.Users
where AppAccess=N'Yes'
    and Username=@userName and [Password]=@password 
order by <<criteria if there are more than 1 matching rows>>
Go

【讨论】:

非常感谢先生。问题是 web 服务将用于具有选项卡布局的 android 应用程序。每个选项卡对应一个部门。每个用户也是如此。我们想要的是,当用户输入他的凭据时,用户名和密码将是调用存储过程的 web 服务方法的输入。如果用户名和密码正确并且用户可以访问应用程序,那么程序应该返回他对应的部门,这样在我的应用程序中我会在登录后将他引导到相应的选项卡。 抱歉,评论太长了,我想澄清一下 Web 服务和存储过程的用途,以便我可以从您的建议中受益 你没有澄清,但我只想强调不要在应用程序、Web服务和数据库之间发送密码的重要性;数据库不应存储密码 - 无论是加密的还是未加密的。密码在被发送或在任何地方使用之前应始终由应用程序进行哈希处理,并且只应存储哈希值,最好是加盐。如果其哈希与存储的哈希匹配,则您的密码是正确的。这样,当您的数据库被黑客入侵并且您的所有密码被盗时,您将不会出现在下一个全球媒体公告中;-)【参考方案2】:

RETURN 只能返回 int。您已经使用了OUT 参数,您应该删除存储过程末尾的return @defaultTabApp 语句。

【讨论】:

谢谢先生。我按照您的建议删除了 return 语句,它起作用了。只是为了理解一件事,如果使用了out参数,则应该没有返回。所以如果我想从存储过程中得到一个值,return 语句不是这样做的方法 不完全是,你可以有输出参数和返回值;调用 app/function/proc 对它们的处理方式不同。返回值只能返回一个整数,一般用于表示成功或失败,输出参数可以是任何值。【参考方案3】:

替换

Declare @defaultTabApptemp NVARCHAR(20)
set @defaultTabApptemp ='NoAccess'
BEGIN TRANSACTION
    if EXISTS(SELECT Top 1  [userId],[userName] FROM [dbo].[users] WHERE [userName]=@userName AND [password]=@password AND [AppAccess]=N'Yes') 
    Begin
       set @defaultTabApptemp = (select Top 1 [dbo].[users].[defaultTabApp] FROM [dbo].[users] WHERE [userName]=@userName AND [password]=@password AND [AppAccess]=N'Yes')
    end
 select @defaultTabApp =  @defaultTabApptemp 

COMMIT TRANSACTION
return @defaultTabApp

Declare @defaultTabApptemp NVARCHAR(20)

 select Top 1  @defaultTabApptemp=[dbo].[users].[defaultTabApp] FROM [dbo].[users] 
WHERE [userName]=@userName AND [password]=@password AND [AppAccess]=N'Yes')
 if @defaultTabApptemp is null  SET @defaultTabApptemp ='NoAccess'
set @defaultTabApp =  @defaultTabApptemp  

【讨论】:

以上是关于System.Data.SqlClient.SqlException:“将 nvarchar 值 'STORES' 转换为数据类型 int 时转换失败。”的主要内容,如果未能解决你的问题,请参考以下文章