快捷搜索:  汽车  科技

java连接mongodb测试(11.Lazarus数据库编程7.ZeosDBO)

java连接mongodb测试(11.Lazarus数据库编程7.ZeosDBO)数据模块声明代码:如下图所示:以上组件除 TZReadOnlyQuery 外,均可以在 Delphi 找到类似的组件,从使用方法的角度来看 ZeosDBO 的组件更加易于使用,而 TZReadOnlyQuery 组件大体上相当于一个只读的 TZQuery 组件。我们可以看到,在 ZeosDBO中,没有事务控制控件,ZeosDBO 会自动为其创建默认的事务控制 。所以,在这里我们就不做过多的介绍,使用时可以参考 Delphi 中类似组件即可轻松地实现应用程序的功能。本节我们通过窗体应用程序实现一个简单的人事档案数据表的 CRUD 操作,数据表结构及数据如下:create table c_dep ( dep_id varchar(64) primary key dep_name varchar(16) ); insert into c_dep (dep_id dep_nam

7.ZeosDBO Database CRUD7.1 CRUD

CRUD 是一个计算机术语,是指在进行计算处理时的增加(Create)、检索(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写。CRUD 主要被用在描述软件系统中数据库或者持久层的基本操作功能。

某些计算机语言,在实际应用中,创造了大量的术语,CRUD 只是其中的一个而已。对于 Delphi、Lazarus 来说,做这个简单的事情简直是小菜一碟。

某些语言为什么会提出 CRUD 这个概念? 这些语言一般是没有指针,表达复杂数据能力不足,所以提出分层概念,我们来看看这些概念:

  • VO - Value Object 负责内存中保存数据的对象。相当于 Pascal 的 Type Record
  • MVC - Modal View Control 其实相当于 Dataset Form Control 编码
  • DAO - Data Access Object 相当于 Dataset Connection

这些概念的提出是为了将程序编写划分更细,维护更方便;而 Lazarus 这样的开发方式也可以实现这些概念,但说实话,真的没有必要。首先是因为 FCL 这样的库克已经非常优秀,而且如 Dataset、MemDataset 这样的数据结构已经能够表达出足够强大的功能。所以在开发中建议:我们还是坚持原生的开发方法。当然以后也可以研究和学习一下这些分层方法,当然如果您已经接触过这些概念就不必学习和研究了(本来也很简单)。这些东西在 Delphi、Lazarus中,如果在实际开发中使用,相当于画蛇添足,多此一举。

7.2 ZeosDBO 常用组件
  • TZConnection
  • TZQuery
  • TZTable
  • TZStoredProc
  • TZReadOnlyQuery

以上组件除 TZReadOnlyQuery 外,均可以在 Delphi 找到类似的组件,从使用方法的角度来看 ZeosDBO 的组件更加易于使用,而 TZReadOnlyQuery 组件大体上相当于一个只读的 TZQuery 组件。我们可以看到,在 ZeosDBO中,没有事务控制控件,ZeosDBO 会自动为其创建默认的事务控制 。所以,在这里我们就不做过多的介绍,使用时可以参考 Delphi 中类似组件即可轻松地实现应用程序的功能。

7.3 窗体应用示例

本节我们通过窗体应用程序实现一个简单的人事档案数据表的 CRUD 操作,数据表结构及数据如下:

create table c_dep ( dep_id varchar(64) primary key dep_name varchar(16) ); insert into c_dep (dep_id dep_name) values ('yfb' '研发部'); insert into c_dep (dep_id dep_name) values ('xsb' '销售部'); insert into c_dep (dep_id dep_name) values ('jszcb' '技术支持部'); insert into c_dep (dep_id dep_name) values ('cwb' '财务部'); insert into c_dep (dep_id dep_name) values ('xzb' '行政部'); create table d_dep_staff ( staff_id varchar(64) primary key dep_id varchar(64) name varchar(32) sex varchar(8) birthday date edu_level varchar(16) school varchar(64) speciality varchar(32) native_place varchar(256) ); INSERT INTO d_dep_staff (staff_id dep_id name sex birthday edu_level school speciality native_place) VALUES(gen_random_uuid() 'yfb' '张三' '女' '1981-9-10' '本科' '内蒙古大学' '经济管理' '内蒙古乌兰察布市集宁区'); INSERT INTO d_dep_staff (staff_id dep_id name sex birthday edu_level school speciality native_place) VALUES(gen_random_uuid() 'xsb' '刘五' '男' '1978-7-11' '本科' '内蒙古大学' '计算机科学与技术' '内蒙古鄂尔多斯市东胜区'); INSERT INTO d_dep_staff (staff_id dep_id name sex birthday edu_level school speciality native_place) VALUES(gen_random_uuid() 'xzb' '弓九' '女' '1983-3-10' '本科' '内蒙古科技大学' '计算机科学与技术' '内蒙古呼和浩特市托克托县'); SELECT staff_id s.dep_id name sex birthday edu_level school speciality native_place d.dep_name FROM d_dep_staff s left join c_dep d on s.dep_id = d.dep_id;

本例也是一个基于 PostgreSQL 数据库,采用 ZeosDBO 数据库组件开发的一个综合示例,设计如下:

7.3.1 数据模块

如下图所示:

java连接mongodb测试(11.Lazarus数据库编程7.ZeosDBO)(1)

数据模块声明代码:

TDataModule1 = class(TDataModule) ZConnection1: TZConnection; ZReadOnlyQuery1: TZReadOnlyQuery; // 字段定义 ZReadOnlyQuery1_birthday: TDateField; // 生日 ZReadOnlyQuery1_dep_id: TStringField; // 部门ID ZReadOnlyQuery1_dep_name: TStringField; // 部门名称 ZReadOnlyQuery1_edu_level: TStringField; // 学历 ZReadOnlyQuery1_name: TStringField; // 姓名 ZReadOnlyQuery1_native_place: TStringField; // 籍贯 ZReadOnlyQuery1_school: TStringField; // 毕业学校 ZReadOnlyQuery1_sex: TStringField; // 性别 ZReadOnlyQuery1_speciality: TStringField; // 所学专业 ZReadOnlyQuery1_staff_id: TStringField; // 员工ID private public end;

属性设置如下:

ZConnection1

  • Protocol - postgresql-9
  • HostName - 127.0.0.1
  • Port - 9432
  • User - postgres
  • Password - ***
  • Database - demodb
  • Connected - True

ZReadOnlyQuery1

  • Connection - ZConnection1
  • SQL - SELECT staff_id s.dep_id name sex birthday edu_level school speciality native_place d.dep_name FROM d_dep_staff s left join c_dep d on s.dep_id = d.dep_id
  • Active - True

【备注】对于 ZReadOnlyQuery1 组件要进行字段定义操作,字段定义有助于在表单窗体中读取当前记录的各个字段值。

7.3.2 主窗体

如下图所示:

java连接mongodb测试(11.Lazarus数据库编程7.ZeosDBO)(2)

窗体声明代码:

TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; Button4: TButton; Button5: TButton; Button6: TButton; DataSource1: TDataSource; DBGrid1: TDBGrid; DBNavigator1: TDBNavigator; KeyEdit: TEdit; // 查询关键字输入框 Panel1: TPanel; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure DBGrid1DblClick(Sender: TObject); private public end;

属性设置如下:

DataSource1

  • DataSet - DataModule1.ZReadOnlyQuery1

DBGrid1

  • DataSource - DataSource1
  • Align - alClient
  • Options - dgRowSelect=True

DBNavigator1

  • DataSource - DataSource1
  • VisibleButtons - [nbFirst nbPrior nbNext nbLast]

【备注】对于 DBGrid1 组件,需要进行列定义操作,有助于各个列的标题等显示方式的设置。

7.3.3 表单窗体

如下图所示:

java连接mongodb测试(11.Lazarus数据库编程7.ZeosDBO)(3)

表单窗体上没有数据库相关组件,都是一些表单组件,而且没有使用 TDB* 组件,使用的都是普通组件,所以不在这里列出组件的属性设置。

窗体声明代码:

TForm2 = class(TForm) Button1: TButton; Button2: TButton; NativePlaceEdit: TEdit; SpecialityEdit: TEdit; SchoolEdit: TEdit; EduLevelComboBox: TComboBox; BirthdayDateTimePicker: TDateTimePicker; DepComboBox: TComboBox; NameEdit: TEdit; SexRadioGroup: TRadioGroup; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure FormActivate(Sender: TObject); private public isNew: Boolean; // 标识数据是否为新建 end; 7.3.4 主窗体功能实现

主窗体实现的功能就是各个操作按钮及数据导航组件的操作。

1.数据导航组件的单击事件

数据导航组件的 OnClick 事件会在单击任何一个按钮后都去触发,当我们使用数据导航组件时,会出现数据记录指针指向开头或末尾的情况,当指向开头或末尾时,可能会导致编辑或删除数据出现问题,所以,我们需要对数据记录指针进行调整,代码如下:

procedure TForm1.DBNavigator1Click(Sender: TObject; Button: TDBNavButtonType); begin if DataModule1.ZReadOnlyQuery1.BOF then if DataModule1.ZReadOnlyQuery1.RecordCount > 0 then DataModule1.ZReadOnlyQuery1.First; if DataModule1.ZReadOnlyQuery1.EOF then if DataModule1.ZReadOnlyQuery1.RecordCount > 0 then DataModule1.ZReadOnlyQuery1.Last; end;

2.新建

新建按钮的功能是打开表单窗体,如果返回值是 mrOk ,则表示在表单窗体中已经插入了数据,需要对 DBGrid1 中的数据进行刷新。代码如下:

procedure TForm1.Button1Click(Sender: TObject); begin // 新建 Form2.isNew := True; if Form2.ShowModal = mrOk then begin DataModule1.ZReadOnlyQuery1.Refresh; end; end;

首先,设置表单窗体的 isNew 属性为 True,表示要进行新建数据记录,然后以模式窗体打开,等待窗体关闭,如果窗体返回值为 mrOk,则对数据集组件 ZReadOnlyQuery1 中的数据进行刷新。

3.编辑

编辑按钮的功能与新建按钮相似,代码如下:

procedure TForm1.Button2Click(Sender: TObject); begin // 编辑 if DataModule1.ZReadOnlyQuery1.BOF or DataModule1.ZReadOnlyQuery1.EOF then Exit; Form2.isNew := False; if Form2.ShowModal = mrOk then begin DataModule1.ZReadOnlyQuery1.Refresh; end; end;

4.删除

删除按钮实现的功能是对当前记录进行删除操作,删除后需要对数据记录进行刷新,代码如下:

procedure TForm1.Button3Click(Sender: TObject); var Query: TZQuery; begin // 删除 if DataModule1.ZReadOnlyQuery1.BOF or DataModule1.ZReadOnlyQuery1.EOF then Exit; Query := TZQuery.Create(Self); try Query.Connection := DataModule1.ZConnection1; Query.Close; Query.SQL.Text := 'DELETE FROM d_dep_staff where staff_id = :staffId'; Query.Params.ParamByName('staffId').AsString := DataModule1.ZReadOnlyQuery1_staff_id.Value; Query.ExecSQL; except on D: EDatabaseError do MessageDlg('Error' 'A database error has occurred. Technical error message: ' D.Message mtError [mbOK] 0); end; Query.Destroy; DataModule1.ZReadOnlyQuery1.Refresh; end;

在上面的代码中,声明了一个 TZQuery 查询对象,在删除按钮的事件中,使用该对象执行 Delete 语句。

5.刷新

刷新按钮的功能很简单,直接调用数据模块中的 TZQuery 组件的 Refresh 方法即可。代码如下:

procedure TForm1.Button4Click(Sender: TObject); begin // 刷新 DataModule1.ZReadOnlyQuery1.Refresh; end;

6.查询

查询按钮实现在关键字输入框中输入内容,根据输入内容进行数据查询,本例没有使用 Filter,而是使用直接执行SQL 语句进行查询,代码如下:

procedure TForm1.Button5Click(Sender: TObject); begin // 查询 if KeyEdit.Text = '' then begin MessageDlg('提示' '请输入查询关键字!' mtError [mbOK] 0); Exit; end; with DataModule1 do begin ZReadOnlyQuery1.Close; ZReadOnlyQuery1.SQL.Text:='SELECT staff_id s.dep_id name sex birthday edu_level school speciality native_place d.dep_name FROM d_dep_staff s left join c_dep d on s.dep_id = d.dep_id WHERE concat(name sex edu_level school speciality native_place d.dep_name) like :Key'; ZReadOnlyQuery1.Params.ParamByName('Key').AsString:='%' KeyEdit.Text '%'; ZReadOnlyQuery1.Open; end; end;

7.全部

全部按钮实现将数据全部显示出来,主要是在关键字查询后回到全部显示的状态。代码如下:

procedure TForm1.Button6Click(Sender: TObject); begin // 全部 with DataModule1 do begin ZReadOnlyQuery1.Close; ZReadOnlyQuery1.SQL.Text:='SELECT staff_id s.dep_id name sex birthday edu_level school speciality native_place d.dep_name FROM d_dep_staff s left join c_dep d on s.dep_id = d.dep_id'; ZReadOnlyQuery1.Open; end; end;

8.DBGrid1 的双击事件

为了方便用户操作,一般情况下,我们需要当用户双击数据网格时进入编辑功能,所以,DBGrid1 的双击事件应该直接调用编辑按钮的单击事件,代码如下:

procedure TForm1.DBGrid1DblClick(Sender: TObject); begin // 双击修改 Button2Click(Sender); end; 7.3.5 表单窗体功能实现

表单窗体的功能主要实现记录的新建和修改,不管是新建记录还是编辑记录,表单窗体中的组件均需要做初始化,新建时,将表单窗体中的各个组件置为初始数据,字符串一般为空字符串,日期为当前日期,类似性别这样的单选数据置一个常用的数据等,编辑时,将表单窗体中的各个组件的值设置为当前记录数据的值,以便于修改;另外,无论是新建还是修改,都需要对列表数据进行初始化,也就是读取数据表中的数据作为列表中的选项,如本例中的所在部门就是从部门表中读取数据并初始化到 ComboBox 组件中。

1.表单窗体初始化

procedure TForm2.FormActivate(Sender: TObject); var Query: TZQuery; index: Integer; begin // 初始化部门选项 try Query := TZQuery.Create(Self); Query.Connection := DataModule1.ZConnection1; Query.Close; Query.SQL.Text := 'SELECT dep_id dep_name FROM c_dep'; Query.Open; DepComboBox.Items.Clear; while not Query.EOF do begin DepComboBox.Items.AddObject( Query.FieldByName('dep_name').AsString TObject(NewStr(Query.FieldByName('dep_id').AsString)) ); Query.Next; end; except on D: EDatabaseError do MessageDlg('Error' 'A database error has occurred. Technical error message: ' D.Message mtError [mbOK] 0); end; // 初始化数据项 if isNew then begin NameEdit.Text:=''; SexRadioGroup.ItemIndex:=0; SchoolEdit.Text:=''; SpecialityEdit.Text:=''; NativePlaceEdit.Text:=''; end else with DataModule1 do begin NameEdit.Text:=ZReadOnlyQuery1_name.Value; if ZReadOnlyQuery1_sex.Value = '男' then SexRadioGroup.ItemIndex:=0 else SexRadioGroup.ItemIndex:=1; index := DepComboBox.Items.IndexOf(ZReadOnlyQuery1_dep_name.Value); DepComboBox.ItemIndex:=index; BirthdayDateTimePicker.Date := ZReadOnlyQuery1_birthday.Value; EduLevelComboBox.Text := ZReadOnlyQuery1_edu_level.Value; SchoolEdit.Text := ZReadOnlyQuery1_school.Value; SpecialityEdit.Text:=ZReadOnlyQuery1_speciality.Value; NativePlaceEdit.Text:= ZReadOnlyQuery1_native_place.Value; end; end;

在上面的代码中,第一部分是对部门选项 DepComboBox 中的列表数据进行初始化,该部分使用了过程中声明的 TZQuery 组件执行对应的 SQL:SELECT dep_id dep_name FROM c_dep,然后遍历 TZQuery 组件中的数据行,逐行读取字段值填充到 DepComboBox 组件的 Items 属性中。

DepComboBox.Items.AddObject( Query.FieldByName('dep_name').AsString TObject(NewStr(Query.FieldByName('dep_id').AsString)) ); Query.Next;

第二部分则根据 isNew 的值来决定对窗体上组件的初始化方式。

2.取消

取消按钮的单击事件很简单,代码如下:

procedure TForm2.Button2Click(Sender: TObject); begin // 取消 ModalResult := mrCancel; end;

3.确定

确定按钮的单击事件就是根据 isNew 的值来决定执行 Insert 还是 Update Sql 语句。代码如下:

procedure TForm2.Button1Click(Sender: TObject); var Query: TZQuery; index: Integer; depId: String; begin // 确定 if NameEdit.Text = '' then begin MessageDlg('提示' '请输入姓名!' mtError [mbOK] 0); Exit; end; if DepComboBox.ItemIndex < 0 then begin MessageDlg('提示' '请选择所在部门!' mtError [mbOK] 0); Exit; end; index := DepComboBox.ItemIndex; depId := PAnsiString(DepComboBox.Items.Objects[index])^; Query := TZQuery.Create(Self); try Query.Connection := DataModule1.ZConnection1; Query.Close; if isNew then begin Query.SQL.Text := 'INSERT INTO d_dep_staff (staff_id dep_id name sex birthday edu_level school speciality native_place) VALUES(gen_random_uuid() :depId :name :sex :birthday :eduLevel :school :speciality :nativePlace)'; Query.Params.ParamByName('depId').AsString := depId; Query.Params.ParamByName('name').AsString := NameEdit.Text; if SexRadioGroup.ItemIndex = 0 then Query.Params.ParamByName('sex').AsString := '男' else Query.Params.ParamByName('sex').AsString := '女'; Query.Params.ParamByName('birthday').AsDate := BirthdayDateTimePicker.Date; Query.Params.ParamByName('eduLevel').AsString := EduLevelComboBox.Text; Query.Params.ParamByName('school').AsString := SchoolEdit.Text; Query.Params.ParamByName('speciality').AsString := SpecialityEdit.Text; Query.Params.ParamByName('nativePlace').AsString := NativePlaceEdit.Text; Query.ExecSQL; end else begin Query.SQL.Text := 'UPDATE d_dep_staff SET dep_id=:depId name=:name sex=:sex birthday=:birthday edu_level=:eduLevel school=:school speciality=:speciality native_place=:nativePlace WHERE staff_id=:staffId'; Query.Params.ParamByName('depId').AsString := depId; Query.Params.ParamByName('name').AsString := NameEdit.Text; if SexRadioGroup.ItemIndex = 0 then Query.Params.ParamByName('sex').AsString := '男' else Query.Params.ParamByName('sex').AsString := '女'; Query.Params.ParamByName('birthday').AsDate := BirthdayDateTimePicker.Date; Query.Params.ParamByName('eduLevel').AsString := EduLevelComboBox.Text; Query.Params.ParamByName('school').AsString := SchoolEdit.Text; Query.Params.ParamByName('speciality').AsString := SpecialityEdit.Text; Query.Params.ParamByName('nativePlace').AsString := NativePlaceEdit.Text; Query.Params.ParamByName('staffId').AsString := DataModule1.ZReadOnlyQuery1_staff_id.Value; Query.ExecSQL; end; except on D: EDatabaseError do MessageDlg('Error' 'A database error has occurred. Technical error message: ' D.Message mtError [mbOK] 0); end; Query.Destroy; ModalResult := mrOk; end;

上面的代码中,仍然是使用过程中声明的 TZQuery 变量来执行 SQL 语句来完成新增或更新。

7.4 CRUD 典型代码

通过上面的代码,我们可以看到,在实际开发中,如果采用这种方式来开发(不使用 *Query 组件的写入,DBGrid组件只用于显示数据),比较典型的代码如下:

Query := TZQuery.Create(Self); try Query.Connection := DataModule1.ZConnection1; // 设置连接 Query.Close; Query.SQL.Text := '......'; Query.Params.ParamByName('staffId').AsString := ......; Query.ExecSQL; except on D: EDatabaseError do MessageDlg('Error' 'A database error has occurred. Technical error message: ' D.Message mtError [mbOK] 0); end;



猜您喜欢: