Delphi XE7 中的登录程序出现错误:参数对象定义不正确.提供的信息不一致或不完整



我在用Delphi编写的一个简单而基本的程序中遇到了以下问题。这是一个登录程序,用户在其中输入用户名和密码。然后,程序将从访问数据库中获取密码,其中用户名等于用户输入的用户名。然后程序将从访问数据库中获得的密码与用户输入的密码进行比较。

这是我的代码副本:

(我有以下变量:密码,用户名,密码)

Username := edtUsername.Text;
Password := edtPassword.Text;
UserQuery.SQL.Add('Select Password as Password1 from Users where Username = :Username');
UserQuery.Parameters.ParamByName('Username').Value := Username;
UserQuery.Open;
sPassword := UserQuery['Password1'];
if sPassword = Password then
begin
  showmessage('Correct');
end
else
begin
  showmessage('Incorrect');
end;

它将查询值保存到变量。如果用户名正确且用户输入的密码正确,则程序工作正常。我的问题是第二次,或者如果用户输入了错误的用户名或密码之类的内容,它会给我一个错误:参数对象定义不正确。提供的信息不一致或不完整。我认为它必须检查查询是否存在,但我不知道该怎么做。如何解决这个问题?

(我还是学习者)

问题是,每次执行方法时,您都会在查询中添加一个 SQL 语句。如果在调试时检查其值,或者只是ShowMessage(UserQuery.SQL.Text),您将清楚地看到它

它将看起来像这样:

Select Password as Password1 from Users where Username = :Username
Select Password as Password1 from Users where Username = :Username
Select Password as Password1 from Users where Username = :Username
...

然后查询失败,因为从第二个到最后一个:Username参数,没有提供任何值

有几种方法可以修复它。其中一个可能涉及清除查询,然后再次分配 SQL 语句:

UserQuery.Clear; // clear the query before adding the SQL statement 
UserQuery.SQL.Add('Select Password as Password1 from Users where Username = :Username');
UserQuery.Parameters.ParamByName('Username').Value := Username;
UserQuery.Open;

或者,您可以直接分配给 Text 属性,该属性将用新提供的值替换整个字符串:

UserQuery.SQL.Text := 'Select Password as Password1 from Users where Username = :Username';
UserQuery.Parameters.ParamByName('Username').Value := Username;
UserQuery.Open;

由于您一遍又一遍地使用相同的查询,因此最理想的设置是初始化它(例如在构造函数上)并将其保留为Prepared状态。预解析准备好的 SQL 语句并将其发送到数据库引擎,使其准备好执行。当您有一个查询或命令需要一遍又一遍地执行并且您唯一更改的是参数值(只是您的情况)时,应该使用它

procedure TForm1.Create(Sender: TObject);
begin
    UserQuery.SQL.Text := 'Select Password as Password1 from Users where Username = :Username';
    // it's a good practice to set the parameter type
    UserQuery.Parameters.ParamByName('Username').DataType := ftString;
    // prepares the query: preparses sql, sends it to the DB engine, etc
    UserQuery.Prepared := True;
end;
// usage
procedure TForm1.YourLoginMethod;
begin
    UserQuery.Parameters.ParamByName('Username').Value := Username;
    UserQuery.Open;
    try
      sPassword := UserQuery.FieldByName('Password1').AsString;
      // perform login logic
    finally
      UserQuery.Close;
    end;  
end;

还有几件事要注意。我建议,类似于设置参数DataType,您使用类型安全的TField属性,又名.AsString.AsInteger

TDataSetdefault property将返回给定字段值的Variant,并执行隐式转换。我建议明确,因为您比 RTL 更了解您的数据类型

这里还需要一个try-finally块。使用准备好的查询时,每次执行它们时,都需要有一个封闭的查询,设置参数,然后调用 open。try-finally 将授予每次打开查询时,无论可能出现的执行如何,它都将被关闭。

最新更新