【问题标题】:ADOQuery to save new and update recordADOQuery 保存新记录和更新记录
【发布时间】:2017-08-01 08:54:53
【问题描述】:

我创建了一个 TForm 来在 Access 数据库中创建新用户。

我创建了 DBedit1,它使用更改事件更新 Edit1。如果在我的 TEdit 文件中输入全新的数据并在插入查询时按保存,它会毫无问题地保存数据。

procedure TFNewUser.BtnSaveClick(Sender: TObject);
begin
    if (Edit1.Text = '') or (Edit2.Text='') or (Edit3.Text='') or (Edit4.Text='') then begin
        ShowMessage('Please enter the missing data!')
    end else if (Edit3.Text) <> (Edit4.Text) then begin
        ShowMessage('Password not match!')
    end else begin
        adoQuery1.Close();
        adoQuery1.SQL.Clear;
        adoQuery1.SQL.Add('INSERT INTO taccount (UserN,FName,Pword,ID)VALUES');
        adoQuery1.SQL.Add('(:UserN,:FName,:Pword,:ID)');
        adoQuery1.Parameters.ParamByName('UserN').Value:= Edit2.Text;
        adoQuery1.Parameters.ParamByName('FName').Value:= Edit1.Text;
        adoQuery1.Parameters.ParamByName('Pword').Value:= Edit3.Text;
        adoQuery1.Parameters.ParamByName('ID').Value:= Edit5.Text;
        Adoquery1.ExecSQL;
        ShowMessage('New user created successfully');
    end;
    ADOQuery1.close;
    ADOQuery1.SQL.text:='select * from taccount';
    ADOQuery1.Open;
end;
  1. 当用户点击 BtnNew 时,在 TEdit 字段中输入新记录,然后按下保存保存新记录 - 是否可以在无需用户输入的情况下为记录分配自动编号。

  2. 但是如果数据从现有记录加载到 Tedit 中,如何通过按 BtnSave 进行更新。

【问题讨论】:

  • 如果你真的在使用 TDBEdit,那么让 TEdit 填写相同的字段是没有意义的,只会让调试变得更加复杂。坚持使用 TDBEdit 或 TEdit(如果必须),但不要将两者混合使用,这会导致问题/不一致,尤其是在您稍后更新表单时。
  • @MartynA 你知道我为什么使用 Tedit,因为如果用户在 TDBEdit 中更改任何内容,它会在没有任何保存命令的情况下在数据库中更改 - 目前,我隐藏 TDBEdit 并将数据放入 Tedit。那么在按下保存按钮之前,即使用户在 TDBEdit 中更改也不会在数据库中更改??
  • 只有在调用数据集的Post方法时,通过 TDBEdit 输入的更改才会发布到 DB。不幸的是,如果任何操作导致数据集导航到不同的记录,则调用此方法,例如使用单击 TDBGrid 中的不同行或 TDBNavigator 的导航按钮。您可以通过使用数据集的 BeforeScroll 事件来避免这种行为。如果你愿意,我可以给你一个例子作为答案(只是提一下,以防有人打败我!)
  • @MartynA 我有两个按钮 btnsave 和 btnnew 当 btnnew 单击 tdedit 清除文件并且用户输入数据并按下另存为新记录时,如果用户尝试编辑退出数据,则它不应该在 DB 中更改,直到保存按钮没有按下,所以这里的问题是我不知道如何在 btnsave 中嵌入和更新,条件是它是新记录还是更新并退出!

标签: sql delphi ms-access delphi-xe8 tadoquery


【解决方案1】:

对于您实际提出的问题,Kobik 已为您提供了一个很好的答案。我想 我会发布这个来告诉你你不需要 TEdits,你可以离开 所有的工作都交给了 TDBEdit 和 TDBNavigator 等支持 DB 的控件。

如果您按照编写的方式编译和运行项目,您会在 单击 DBNavigator 中的+ 按钮,AdoQuery 进入插入模式 并且鼠标光标放置在 UserN DBEdit 中,以便您可以开始填充 在新的用户记录中。

有一个 btnSave 是您应该保存记录的方式。我有 提供这个按钮仅仅是因为你有一个。请注意,如果单击 DBNavigator 上的保存按钮,您会收到一条消息,说明保存按钮 没有被点击,插入操作被取消,新的用户数据 被丢弃。

项目中的大部分代码都是必需的,因为它是在模仿您的 使用单独的保存按钮。为了说明这一点,将项目更改如下

  • 将 btnSave 的 Visible 属性设置为 false

  • CheckSaveButtonClicked 的第一行,在if ... 之前添加一个Exit

& 再次编译/运行项目。

您会发现 DBNavigator 上的保存按钮现在可以正常工作,并且项目 从 DBNavigator 的行为的角度来看, 正如用户直观地期望的那样。

所以事实上,如果您按照预期使用 DBNavigator,则没有任何代码 在项目中是必需的ATALL,除了DBEdit1.SetFocus 放置鼠标 在插入操作开始时,光标在此控件中,当然还有AdoQuery1.open。这就是为什么我说 在评论中,如果您使用它们,您可以将工作留给 DB 感知控件 正确。

更新

您建议我如何使用“自定义>消息”限制用户输入重复的用户名,我认为应该在发布前添加

就个人而言,我认为在将新记录插入数据库之前避免重复和进行其他验证的最佳方法是最初将其添加到单独的本地表中(例如 TClientDataSet 或FireDAC TFDMemTable)。然后,一旦用户输入了足够的信息来检查重复项并执行您想要的任何其他验证,您就可以提醒用户任何问题并让他们更正它们。新记录“干净”后,将其从本地表复制到主表。

这样做允许您使用 db-aware 控件让用户输入新记录数据。此外,就个人而言,对于实际应用程序,我一直要求用户使用特殊的“新记录向导”作为单独的表单,其中包含本地输入表的 db-aware 控件;通常这是一个多标签表单,除了非常简单的情况。这比其他一些方法更费力,例如使用为编辑 existing 记录而提供的 db-aware 控件,但效果更好,并且允许您捕获某些难以或不可能执行的错误如果用户直接将新记录输入到主表中。

代码

type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    DBNavigator1: TDBNavigator;
    DataSource1: TDataSource;
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    ADOQuery1ID: TAutoIncField;
    ADOQuery1UserN: TStringField;
    ADOQuery1FName: TStringField;
    ADOQuery1Pwd: TStringField;
    DBEdit1: TDBEdit;
    DBEdit2: TDBEdit;
    DBEdit3: TDBEdit;
    btnSave: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure ADOQuery1BeforeEdit(DataSet: TDataSet);
    procedure ADOQuery1BeforeInsert(DataSet: TDataSet);
    procedure ADOQuery1BeforePost(DataSet: TDataSet);
    procedure btnSaveClick(Sender: TObject);
  private
    procedure CheckSaveButtonClicked;
    function GetSaveEnabled: Boolean;
    procedure SetSaveEnabled(const Value: Boolean);
  protected
  public
    SaveClicked : Boolean;
    property SaveEnabled : Boolean read GetSaveEnabled write SetSaveEnabled;
  end;
[...]
procedure TForm1.FormCreate(Sender: TObject);
begin
  SaveEnabled := False;
  AdoQuery1.Open;
end;

procedure TForm1.ADOQuery1BeforeEdit(DataSet: TDataSet);
begin
  SaveEnabled := True;
end;

procedure TForm1.ADOQuery1BeforeInsert(DataSet: TDataSet);
begin
  SaveEnabled := True;
  DBEdit1.SetFocus;
end;

procedure TForm1.CheckSaveButtonClicked;
begin
  if not SaveClicked then begin
    AdoQuery1.Cancel;
    ShowMessage('Save button not clicked');
    Abort;   //  In case the user clicked the DBNavigator Save button
  end;
end;

procedure TForm1.ADOQuery1BeforePost(DataSet: TDataSet);
begin
  CheckSaveButtonClicked;
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  SaveClicked := True;
  AdoQuery1.Post;
  SaveEnabled := False;
end;

function TForm1.GetSaveEnabled: Boolean;
begin
  Result := btnSave.Enabled;
end;

procedure TForm1.SetSaveEnabled(const Value: Boolean);
begin
  btnSave.Enabled := Value;
  SaveClicked := False;
end;

DFM 内容

object Form1: TForm1
  Left = 259
  Top = 103
  AutoScroll = False
  Caption = 'MADefaultForm'
  ClientHeight = 314
  ClientWidth = 444
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  Scaled = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 48
    Top = 201
    Width = 30
    Height = 13
    Caption = 'UserN'
  end
  object Label2: TLabel
    Left = 48
    Top = 225
    Width = 34
    Height = 13
    Caption = 'FName'
  end
  object Label3: TLabel
    Left = 48
    Top = 249
    Width = 21
    Height = 13
    Caption = 'Pwd'
  end
  object DBGrid1: TDBGrid
    Left = 40
    Top = 8
    Width = 320
    Height = 153
    DataSource = DataSource1
    TabOrder = 0
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'MS Sans Serif'
    TitleFont.Style = []
  end
  object DBNavigator1: TDBNavigator
    Left = 48
    Top = 168
    Width = 240
    Height = 25
    DataSource = DataSource1
    TabOrder = 1
  end
  object DBEdit1: TDBEdit
    Left = 85
    Top = 198
    Width = 121
    Height = 21
    DataField = 'UserN'
    DataSource = DataSource1
    TabOrder = 2
  end
  object DBEdit2: TDBEdit
    Left = 85
    Top = 222
    Width = 121
    Height = 21
    DataField = 'FName'
    DataSource = DataSource1
    TabOrder = 3
  end
  object DBEdit3: TDBEdit
    Left = 85
    Top = 246
    Width = 121
    Height = 21
    DataField = 'Pwd'
    DataSource = DataSource1
    TabOrder = 4
  end
  object btnSave: TButton
    Left = 288
    Top = 240
    Width = 75
    Height = 25
    Caption = 'Save'
    TabOrder = 5
    OnClick = btnSaveClick
  end
  object DataSource1: TDataSource
    DataSet = ADOQuery1
    Left = 112
    Top = 8
  end
  object ADOConnection1: TADOConnection
    Connected = True
    ConnectionString =
      'Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security In' +
      'fo=False;Initial Catalog=MATest;Data Source=MAT410\ss2014'
    LoginPrompt = False
    Provider = 'SQLOLEDB.1'
    Left = 32
    Top = 8
  end
  object ADOQuery1: TADOQuery
    Connection = ADOConnection1
    BeforeInsert = ADOQuery1BeforeInsert
    BeforeEdit = ADOQuery1BeforeEdit
    BeforePost = ADOQuery1BeforePost
    Parameters = <>
    SQL.Strings = (
      'select * from taccount')
    Left = 72
    Top = 8
    object ADOQuery1ID: TAutoIncField
      FieldName = 'ID'
      ReadOnly = True
    end
    object ADOQuery1UserN: TStringField
      FieldName = 'UserN'
      Size = 50
    end
    object ADOQuery1FName: TStringField
      FieldName = 'FName'
      Size = 50
    end
    object ADOQuery1Pwd: TStringField
      FieldName = 'Pwd'
      Size = 50
    end
  end
end

【讨论】:

  • 错误,阻止?你认为它缺少什么代码?我发布的代码是我的整个项目,除了表单变量声明+实现标题等,[...] 是。
  • 像魅力和服务器一样工作也很好,我有一个快速的问题,我正在使用 RAD studio XE8 我有一个奇怪的问题,当我按下 IDE 中的输入文本行时,为什么没有移动到下一行?跨度>
  • 抱歉,不知道 XE8 IDE,它对我来说很好用。我建议您发布一个新的 q,并尽可能地用一两个屏幕截图说明问题。
  • 我发的问题其实是覆盖心情只需要按INS回到插入心情。
  • 先生,您能建议我如何限制用户使用“自定义消息”输入重复的用户名,我认为应该在发布前添加。
猜你喜欢
  • 2013-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多