1. 新事务不能登记到指定的事务处理器中
现象:登录时输入用户和密码回车后,报错,这个只在连接数据库服务器时才会出现,如果中间层和数据库都地本机上,是不会出现的。
临时处理方法:
只有在中间层的事务方式为:“必需/要求新建”时才会报这个错误,调试程序时可以临时把中间层的事务方式改为“支持”,但是记住这只是临时的处理方式,这种方式会引起使用主从表的数据集保存失败,例如用户管理里的功能调整,就会报错
2. 找不到指定模块
现象:从组件服务看中间层已经安装,程序中还是报错“找不到指定模块”
原因:中间层DLL文件所在的目录不对
处理方法:
在中间层小球上点右键,看属性,把DLL文件所在的目录拷出来,记住只拷目录,不带文件名,粘贴到我的电脑的地址栏里,回车,然后看目录里到底有没有需要的中间层DLL文件了。
3. 没有注册类别
现象:程序登录或使用中报错“没有注册类别”
原因:1.系统所需要的中间层没装,2.程序中连接本地中间层了
处理方法:(我觉得处理方法就是处理的步骤,不知道这样改行不行)
1.通过查看INI文件来判断程序连接的是本地中间层还服务器中间层。
2.如果是服务器中间层,查是否连接了本地中间层:是不是把中间层在本地装一下,就不报错了,如果是这种现象,那就是连本地中间层了。
3.如果把中间层在本地装上之后还是报错,那就是模块需要的中间层没装全,现在的程序很多都需要相关的中间层,例如使用wpws需要yz的中间层。
4.程序需要的中间层已经装全了,还是报没有注册类别,有可能是客户端目录里有被程序调用的DLL文件,这些DLL文件中有一个或几个需要独立的中间层,可以先把客户端exe所在目录的所有DLL清空,再试一下,如果不报错了,那就是这个原因,通过逐步增加DLL的方式判断出哪个DLL的中间层没装,然后装上。
4. 找不到1%。
原因:C:\Program Files\Common Files\System\Ole DB\Data Links 目录下缺少 chis.udl 文件
5. 不正确地定义参数对象。提供了不一致或不完整的信息。
原因:1.中间层 adoquery 的参数和客户端组件 clientdataset 的参数数量不一致
2.参数的默认值为 null并且open之前没给参数赋值,这种错误在调试的时候经常出现,修改过adoquery的SQL语句之后,直接在delphi环境里双击clientdataset控件的active属性就有可能出现。
6. 报错adq….缺少字段
原因:1.数据库中没有这个字段
2.数据库中有,但是adq.…的SQL语句里没有取这个字段,取固定列的时候发生。
7. 报错 cds....缺少字段
原因:1.数据库中没有这个字段
2.数据库里有,但是对应的adq….的SQL语句里没取这个字段
3.数据库里有,对应的adq….的SQL语句里也取了这个字段,但是adq….是取固定列的,固定列中不包括这个字段
4.cds….是取固定列的,固定列中没有包含这个字段
5.主从表的时候如果复制主表的clientdataset,原固定列没清除。
8. 更新、删除数据失败
原因:1.clientdataset.applyupdates 时自动生成的 update 或 delete 语句条件中某个字段的数据带毫秒
2. 如果clientdataset刚做过数据添加,在没有重新读取数据的情况下,做更新或删除,where条件中某个字段的数据在数据库的设置中有默认值,并且在记录insert 的时候并没有给默认值赋值
3.where条件中某个文本字段中有特殊值,例如“,,”
4.触发器
处理方法:
1.清除带毫秒的datetime型数据中的毫秒部分
2. 通过adoquery属性设置为datetime型的字段不做为条件
3.通过中间层的设置或代码控制,使带毫秒的datetime型字段不做为条件
在中间层的adoquery的afteropen事件里写代码:
procedure Tyz_act_order_stop.adqGetdataAfterOpen(DataSet: TDataSet);
begin
DataSet.FieldByName('order_name').ProviderFlags := [];
DataSet.FieldByName('order_name').ProviderFlags := [pfInUpdate];
End;
4.在客户端添加数据的时候给带默认值的字段赋值
5.使带有特殊字值的文本字段(yz_comment、instruction、discription)不做为条件
9. rpc服务器不可用
原因:1.客户端闲置时间过长,中间层自动关闭
2.调试程序的过程中,手动关闭了中间层
处理方法:clientdataset1.remoteserver.close;把这句代码放在clientdataset1.close之前。
10. 点击按钮时,什么错都不报,跟踪什么都没有
原因:1.代码中使用了(try except end)直接的错误提示信息被拦截了
处理方法:
try
……..
except
on E: Exception do
begin
ShowMessage('dll_ypApply初始化失败:'+E.Message);
Exit;
end;
end;
11. 循环更新数据集时,只更新了一部分(有时是一半),另一部分没更新(或者循环计算汇总,汇总出来数据不对,有时候多,有时候少)
原因:1.数据集上有filter,并且修改数据集的数据时修改了和filter有关的字段,导致post之后,当前数据集已经不可见,但还是继续执行了循环中的next。
2.循环的数据集上有排序,循环过程中修改了排序字段,导致有部分数据重复参与汇总,有部分数据没有参与汇总
12. 数据集savetofile之后明明有满足条件的数据,但是locate不到
原因:数据集有filter,所以locate查不到,而且RecordCount也是受filter影响的,但是savetofile是忽略filter的,会把数据集里所有的数据都输入到指定的文件里。
13. 怎么样只显示当前这一组父子医嘱,无关的不显示
Var
sActorderno: string;
begin
if clientdataset1.FieldByName(‘parent_no’).asfloat > 0 then
sActorderno := clientdataset1.FieldByName(‘parent_no’).asfloat
else
sActorderno := clientdataset1.FieldByName(‘act_order_no’).asfloat;
clientdataset1.filtered := false;
clientdataset1.filtered := ‘parent_no = ‘ + sActorderno + ’ or act_order_no = sActorderno’;
clientdataset1.filtered := true;
end;
14. 根据条件界面上的内容显示不同的颜色
procedure TfrmChargeOrder.grdChargeShowGetCellParams(Sender: TObject;
Column: TColumnEh; AFont: TFont; var Background: TColor;
State: TGridDrawState);
begin
inherited;
//以背景色区分费用细目的状态。
with Sender as TDBGridEh Do
begin
if TDataSet(DataSource.DataSet).FieldByName('charge_status').Value = '2' then
BackGround := RGB(255,0,50)
else if
TDataSet(DataSource.DataSet).FieldByName('charge_status').Value = '3' then
BackGround := RGB(0,255,0)
else if
TDataSet(DataSource.DataSet).FieldByName('charge_status').Value = '4' then
BackGround := RGB(0,0,255);
AFont.Color := clRed;
end;
end;
15. 客户端增加的窗体看不到
原因:功能里没加这个窗体的权限 ,增加以后要重新登录程序
16. 中间层增加的窗体看不到,中间层新增的函数用不了
原因:1.中间层没有重新安装或没有关闭
2.中间层实际使用的文件和编译输出的文件不在同一个目录里
17. 网页调用delphi写的OCX的时候,没有任何反应
原因:网页中调用OCX时的入参数量和OCX对外公布的入参数量不符
18. 字段只读,无法编辑
原因:1.字段来自固定内容或者计算内容
2.字段来自存储过程,并且是在存储过程中计算得出的
处理方法:
1.在中间层的adoquery的afteropen事件里写代码:
procedure Trt_com_yz_zy_detail_charge.adqPageNoAfterOpen(
DataSet: TDataSet);
begin
DataSet.FieldByName('page_type_external').ReadOnly := False;
end;
2.修改存储过程,使字段从表里取,或者在clientdataset中使用内部计算字段 fkInternalCalc
3.存储过程和视图里写固定值的字段、用函数或表达式处理过的字段是不允许编辑的,如果需要编辑可以建个小的字典表,把值写在表里,然后关联一下。
19. 更新数据集(包括修改、删除)时,报XX字段不存在
原因:报错的字段来自关联表
处理方法:
在中间层的adoquery的afteropen事件里写代码:
procedure Tyz_act_order_stop.adqGetdataAfterOpen(DataSet: TDataSet);
begin
DataSet.FieldByName('order_name').ProviderFlags := [];
End;
20. 更新数据集时,没有可以更新的数据Record not found or changed by another user,记录已经被别人修改
原因:1.当前clientdataset更新的数据,在你取出来之后,提交之前,被其它人修改过。
2.当前要更新的表上某个字段有默认值,并且程序里没有给这个字段赋值,在第一次提交的时候是执行的insert,如果此时没有重新获取数据,编辑之后再次提交,就会报这个错误。
3.数据中某日期时间型字段的有“毫秒”
21. null 导致的取值取错
原因:从字段中取值的时候,字段的值为null
a := ClientDataSet1.FieldByName('deleted_flag').Value;
处理方法:
a := ClientDataSet1.FieldByName('deleted_flag').AsString;
22. chis.ini里的值取不到
原因:组标题有重复。
23. 退出时报地址错
原因:有动态创建的窗体/动态加载的函数未释放
24. 录入控件在自己机器上没问题,但是在工程或现场报错(因为wh_tag_sql 激活状态未设置)
25. 调用接口函数时报地址为 00000000的错误
原因:在调用函数之前未加载
处理方法:在函数使用之前加判断
if Assigned(InitVariant) then
26. 窗体未创建直接show。
如果报地址错了,查到是窗体的show或showmodal报错,可以考虑是不是没有创建或者已经释放了。
27. 窗体创建并使用后未释放,导致再次打开后还留有上次使用的旧数据(取数据的语句放在formcreate里)
原因:初始化窗体的语句放在了formcreate事件里
处理方法:将初始化语句放在formshow事件里
28. 临时数据集未createdataset直接使用
原因:临时数据集(就是取固定列并且没有连接DataSetProvider的数据集),没有经过CreateDataSet或者已经Close就直接使用了
处理方法:在对数据集执行操作之前CreateDataSet
29. FindField的使用,和引出的问题
With cdsZyConfigureAllField Do
begin
Close;
Data := null;
Open;
if FindField('yb_responce_type') <> nil then
gv_yb_responce_type := trim(FieldByName('yb_responce_type').AsString);
end;
可以在使用之判断某字段是否存在,然后根据判断结果执行不同的动作,缺点是由于不报错,工程不知道需要增加这个字段,通用程度不高的字段可以用这种方法处理,通用性比较强的字段如果没有要增加错误提示。
30. 序列号的使用
function Trt_comYzConfiger.iGetOccPageNo: OleVariant; //by swl 2009-11-10 南京鼓楼升级
begin
try
Result := 0;
With adqResult Do
begin
SQL.Clear;
SQL.Append('update yz_configure set occ_page_no = occ_page_no + 1');
ExecSQL;
SQL.Clear;
SQL.Append('select occ_page_no from yz_configure');
Open;
IF RecordCount <> 0 then
begin
Result := FieldByName('occ_page_no').AsInteger ;
end;
Close;
end;
SetComplete;
except
on Exception Do
begin
SetAbort;
Raise;
end;
end;
end;
要注意在设置事务模式的时候,有序列号生成函数的数据窗体,必须选择 Requires a new transaction
31. 调用EXE文件并传入参数
program Project1;
uses
Forms,
Dialogs,
Unit1 in 'Unit1.pas' {Form1};
var
i: Integer;
{$R *.res}
begin
Application.Initialize;
for i := 1 to ParamCount do
begin
ShowMessage(ParamStr(i));
end;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
//调用EXE
WinExec(PChar('d:\project2 a b'), SW_SHOWDEFAULT);
32. 数据类型 char 和 test 在 equal to 运算符中不兼容
原因:adoquery中的sql语句是用 = 作为比较,并且clientdataset中有参数是string类型,在给该赋值的时候实际值是‘’空字符串。
处理方法:在给参数赋值之前,判断一下,如果为‘’空字符串,则赋一个不可能存在的值给参数,或者赋quotedstr(‘’)。
33. 窗体未create,引用其中的clientdataset报错,在with DataModule2.ClientDataSet1 do这条语句就报错了
34. 克隆(什么时候适合用克隆,什么时候适合用ClientDataSet1.Data := ClientDataSet2.Data)
ClientDataSet2.CloneCursor(ClientDataSet1, true);
和
ClientDataSet2.CloneCursor(ClientDataSet1, false);的区别
在复制的数据需要修改并同步到主数据集的时候用克隆,不需要提交的时候用Data赋值,要注意使用克隆的时候,两个数据集不能同时处理编辑状态,否则会出现一方数据修改,另一方没有影响的情况。
ClientDataSet里的计算列、内部计算列在通过.Data赋值,或者客户端传给中间层的时候是无法传递的,但是通过 CloneCursor 克隆数据集,克隆出来的数据集和原始数据集是完全一致的,计算列、内部计算列都有。
35. 多步OLE DB操作产生错误,如果可能,请检查每个OLE DB状态值。没有工作被完成
原因:中间层的adoquery有3个参数,客户端的clientdataset有4个
处理方法:中间层和客户端的参数数量要一致,这种情况一般发生在客户端clientdataset复制的时候,复制完之后没改参数,直接使用报错。
36. 常用调试方法,跟踪程序、跟踪SQL、日志、showmessage。
在程序报错的时候用跟踪的方法找报错的语句,跟踪程序的过程中可以使用Ctrl + F7,调出
查看某一变量的值或者某一控件的属性,并可以修改
Ctrl + F5调出
可以跟踪变量的值的变化情况。
在查询结果或者SQL语句的执行结果和预期不同的时候用跟踪SQL语句的方法,语句优化的时候也可以用,查找运行耗时过长的SQL,有异常数据查产生原因,都和跟踪SQL语句有关。
37. 通过修改表名等方式模拟HIS失败。
38. 主从表
通过datasource连接主表和从表,主从表就是蜂巢结构,这种结构不好控制,有时候莫名其妙的报错,还找不到原因
39. 循环初始化数据时要考虑filter
在对数据集循环进行初始化(例如把某个字段赋值为‘1’或者通过数据和单价计算金额)时,要考虑数据集上有没有打开的filter,如果有,要注意循环里边修改的内容不能包括filter里的条件字段,如果修改了filter里的字段值,会导致初始化结果有问题,可能会有部分数据初始化失败。
40. WINDOWS 消息体系的基础培训
//消息定义(exe和dll都要定义)
WM_CP_test = WM_USER + 3000;
//消息发送(dll)
SendMessage(gv_MainForm_Handle, WM_CP_test, 0, 0);
//消息接收(exe)
procedure _test(var WM_CP_test: Msg); message WM_CP_test;
procedure TfrmMainInput._test(var WM_CP_test: Msg);
begin
showmessage('ok');
end;
通过SendMessage传递字符串
在DLL文件中使用如下代码:
MyId 定义为全局变量 String 类型
SendMessage(Form1.Handle,WM_TEST_END,Integer(@MyId),1);
其中MyId是要返回的字符串
在主窗口中使用如下代码:
先在public中加入消息函数的声明
Delphi代码
procedure WMTestEnd(var AMsg:TMessage);message WM_TEST_END;//消息函数
其中WM_TEST_END是自定义的消息
再在implementation写函数
Delphi代码
procedure TForm1.WMTestEnd(var AMsg:TMessage);
var
s:string;
begin
s:=string(Pointer(AMsg.wParam)^);
Memo1.Lines.Add(s);
end;
需要注意的是,如果你在线程中,一定要使用SendMessage来发送消息,如果使用PostMessage会出错。原因我想是因为 PostMessage发送消息后线程会继续执行下去,当主窗口收到这个消息并处理时,线程可能已经结束了,这时指向字符串的那个指针就会出错;而 SendMessage发送消息后会将线程挂起,直到消息处理完成后,才继续执行下面代码。
41. 多次open有时会影响效率,对于字典可以在窗体创建的时候一次open,中间使用时通过filter或locate取指定的值。
42. ClientDataSet1.DisableControls和 ClientDataSet1.EnableControls
在数据集循环时,界面上的数据感知控件是否响应数据的变化,如果响应界面上显示的内容会狂闪,而且速度很慢,一般在数据量比较大的数据集循环时先关闭DisableControls,循环之后再开启EnableControls。
43. 录入控件的相关的Lookup字段在数据集open之后dbgrid里不显示该字段的值
原因:录入控件只对当前记录进行处理,并保存处理过的Lookup字段的结果值,对于没有滚动过的记录不会处理,所以数据集open之后只有当前行的Lookup字段以及和当前行的code相同的数据行是显示值的,其它的不显示。
处理方法:1.在数据集open之后,把数据集循环一遍,每一条记录执行一次twDBEditDD1. ScrollSelf(twDBEditDD1),这种处理方法适和于数据量比较小的情况。
2.在adoquery里通过关联取出对应的字典name(假设字段名为dept_name,要设置为不提交也不作为条件),在客户端显示字典name,不显示录入控件的Lookup字段的值,在通过录入控件对数据进行修改时,编辑对应的字典name字段dept_name,适用于所有情况。
44. 循环时使数据集的acterscroll事件不执行。
var
eAfterScroll: TDataSetNotifyEvent;
begin
inherited;
try
eAfterScroll := cds_a_employee_mi.AfterScroll;
cds_a_employee_mi.AfterScroll := nil;
with cds_a_employee_mi do
begin
Next;
end;
finally
cds_a_employee_mi.AfterScroll := eAfterScroll;
end;
45. OCX控件在IE中的调试方法
46. 三层程序在win7的环境下使用的主要注意事项
1.midas.dll文件要单独下载,放在windows\system32目录下
2.64位win7除midal.dll之外的dll文件放在SysWOW64目录下而不是System32目录下
47. ini_set_tag_sql配置tag_sql
在窗体的 FormCreate(Sender: TObject);
procedure TfrmInPatient.FormCreate(Sender: TObject);
var
tcm_diag_tag: Integer;
begin
inherited;
.........
tcm_diag_tag := 57;
with cdsExec do
begin
Data := Null;
Close;
CommandText :=
'select tag_count=count(*),tag_sql_id=max(tag_sql_id) from ini_set_tag_sql where subsys_id=''adt'' and form_name=''frmInPatient'' and object_name=''edtTCMDiag'' ';
Open;
if FieldByName('tag_sql_id').AsInteger > 0 then
tcm_diag_tag := FieldByName('tag_sql_id').AsInteger;
end;
Self.edtTCMDiag.SqlTag := tcm_diag_tag;
在给录入控件的 SqlTag 属性赋时,必须保证相连接的 DCOMConnection 的 computername 已经赋值,否则会引起连接本地中间层的Bug。
48. ini_set_report_code配置报表号
procedure TdlgDeposit_yjj.FormCreate(Sender: TObject);
begin
inherited;
iYjjZyReport := 4082; //窗体的私有变量,预交金(在院病人)报表号
with cdsExec do
begin
Close;
Data := Null;
CommandText := 'select yjj_count=count(*),report_code=max(report_code) from ini_set_report_code where subsys_id=''adt'' and form_name=''frmDeposit_yjj'' and form_no=''yjj_zy''';
Open;
if FieldByname('yjj_count').AsInteger > 0 then
iYjjZyReport := FieldByName('report_code').AsInteger;
end;
49. 在界面上显示报表预览
select * from rt_report_data
select * from rt_report_params
rt_report_data.report_flag表示报表类型 1 普通报表 x 交叉报表 f FastReport
步骤:
1.窗体继承自 frmChildprintForm
//以下在窗体的FormCreate中:
2.取自定义报表号(如果是固定报表号,可以省略这个步骤)
//以下在预览按钮的单击事件里:
3.通过 getreportEx(报表号) 或getreport(报表号),getreportEx比getreport多一段代码,暂时没看懂那段代码的功能。
4.给报表中的特殊 qrlabel.caption 赋值,一般是对表头赋值
for i:=0 to selfponentcount-1 do
begin
if components[i] is Tqrlabel then
begin
if components[i].Name='lbl_pid' then
Tqrlabel(components[i]).caption:=
cds_zyactpatient.fieldbyname('inpatient_no').value;
if components[i].Name='lbl_name' then
Tqrlabel(components[i]).caption:=
cds_zyactpatient.fieldbyname('name').value;
if components[i].Name='lbl_bedno' then
Tqrlabel(components[i]).caption:=
cds_zyactpatient.fieldbyname('bed_no').value;
end;
end;
5.给报表参数赋值
with cdsSQLParams do
begin
//病人ID
if Locate('param_name','patient_id',[loPartialKey]) then
begin
Edit;
FieldByName('param_defaultvalue').Value := sPatient_id;
end;
//入院次数
if Locate('param_name','times',[loPartialKey]) then
begin
Edit;
FieldByName('param_defaultvalue').Value := sTimes;
end;
end;
6. getdataEx;
7. PreviewReport;
//以下在打印按钮的单击事件里:
8. PrintReport;
50. 对将要提交的数据集做限制,满足某些条件时才允许提交
1.如果要限制的数据集已经有一些现在的限制,增加的时候采用与现有限制相同的方式来做
2.在befortpost里判断
procedure TdmYzInput.cdsActOrderBeforePost(DataSet: TDataSet);
begin
inherited;
......
if (DataSet.FieldByName('Serial').AsString <> '**') and
(DataSet.FieldByName('supply_code').AsString = '') then
begin
SelectMessageBox('药品医嘱必须录入给药方式!', 1, 1);
TfrmMainInput(CurrentInputForm).edt_supply.SetFocus;
Abort;//这里必须用Abort,用exit起不到限制的作用
end;
3.在数据真正保存之前,循环判断,要注意,在循环之前 DisableControls,循环之后 EnableControls
51. 判断当前记录的状态status(clientdataset1. UpdateStatus)
while not cdsCheck.Eof do
begin
case cdsCheck.UpdateStatus of
usInserted: //插入
begin
......
end;
usDeleted: //删除
begin
......
end;
usModified: //修改
begin
......
end;
end;
cdsCheck.Next;
end;
52. 判断数据集的当前状态(dsinsert,dsedit)
//判断数据
if CdsActOrder.State in [dsEdit, dsInsert] then
CdsActOrder.Post;
判断数据集的当前状态,一般的用法是:
1.在开始编辑之前,判断一下,如果不在编辑状态,则 ClientDataSet1.Edit或ClientDataSet1.Append
2.在ApplyUpdates之前,判断数据集是否在编辑状态,如果在,则post。
53. 通过dll_print.dll打印报表
在ADT源码里,搜索 dll_print.dll 根据找到的内容拷贝。
54. cannot focus a disabled or invisible window
在 DBGrid1.setfocus 的时候,如果 DBGrid1 不能接受焦点(例如Enable = false),就会报这个错误。
55. data := null
对于通过参数赋值再open的数据集,在Close之后,要执行 ClientDataSet1.Data := null,清空旧的数据,再对参数赋值,再open,否则有可能因为旧数据已经存在,导致不执行SQL语句。
56. adoquery 的参数默认值的作用
在ClientDataSet1.applyupdates的时候,系统会首先以默认参数发出adoquery1里写的select 语句,如果这时默认的参数值可以查出10W条数据,就会产生相应的网络流量,数据量越大,速度就会越慢,所以adoquery1里的参数默认值尽量设定为不可能查到数据。
57. EmptyDataSet
保持字段结构不变,清空数据
58. MergeChangeLog
清空所有记录的修改日志,并将ChangCount属性重置为0,如果数据不是直接applyupdtes的,真是通过Delta到中间层里提交,那每次提交之后必须调用 MergeChangeLog。
======================================未讲内容
59. 事务
当一组语句构成一个事务处理时,如果一个语句没有执行成功,则所有的语句都不成功。如果你需要更新多个表中的数据,你不希望对一个表的操作失败,而对其它表的操作成功了。这时就需要用到事务。
60. SQL优化
61. 排序、动态排序
一般是对数据集ClientDataSet中的数据进行排序,可以通过以下几种方式:
1.IndexFieldNames,
2.
62. 焦点的控制
63. 中间层安装时如果报“对象已被注册”,必须处理之后再装一下,否则会有异常,有可能连接的中间层还是老的。
如果当前模块的中间层已经安装,现在想要重新安装一下,如果以前安装的没删除,新安装的时候会报错,“对象已被注册”,这时候新的中间层是没有安装的,必须处理之后再安装一下,否则还是执行的老版本的中间层。
64. 中间层数据类型冲突
这个错误提示表明:数据集ClientDataSet1里的字段py_code定义的是Integer型,SQL语句返回的这个字段的值是String类型
65. Filter对于中文支持不好,如果用 like ‘%中文%’,会查不到数据
66. 凡是客户端dll文件,必须有初始化函数和释放函数。
67. 根事务需要确认,但事务终止了操作(触发器执行失败)
68. 在数据明显超过一屏幕的情况下,DBGrid右侧没有显示上下的滚动条
把DBGrid换成DBGridEh,然后把上下的滚动条设置成始终显示
69. List index out of bounds (0)
参数数量不符,一般是在调用中间层函数的时候,客户端提供的参数和中间层函数实际的参数数量不一致,大部分时候是由于客户端版本和中间层版本不一致造成的,应对方法是发出最新版本的配套程序,或者工程自行找到配置的程序。
70. 在使用颜色的时候尽量不要用类似“clWindowText”这种系统颜色
这种颜色会随着操作系统主题改变,用“clBlue”这种指定的颜色就不会有这种问题
71. 调用动态创建的变量或动态加载的dll函数之前,必须用Assigned判断一下,不能直接调用
原因是如果这个变量(函数)没有创建(加载)会报地址错。
72. Expression expected but nothing found
with ClientDataSet1 do
begin
CreateDataSet;
AppendRecord(['01', '男']);
AppendRecord(['02', '女']);
Filtered := False;
Filter := 'code = ' + '';
Filtered := True;
end;
73. 在程序中禁止使用录入控件的ListSource指定的clientdataset做查询,例如:cdsDict。
74. 中文做为参数的注意事项
使用参数的方式做查询或执行SQL语句的时候,要注意,如果参数的内容有可能是汉字,则需要在参数的内容右边加几个空格,因为参数会把汉字做为一个字符来计算宽度,然后传到中间层的参数尾部就会有一部分内容被截掉,造成参数的内容错误。
75. 关于中间层事务
写中间层函数,必须有SetComplete 和 SetAbort,不管有没有数据需要提交,如果是纯查询的函数,必须写nolock(锁定不更改),建议纯查询的内容放在data中间层,用adoquery来实现,不要写中间层函数。
程序中使用的字典数据集,如果除了即用于filter、locate也用于lookup字段,就必须要清楚,lookup字段的内容是会在数据集Edit的时候对LookupDataSet里关联的数据集进行隐性的locate。
Locate 命令的第三个参数:Options: TLocateOptions,其中参数值 loPartialKey 的作用是:模糊查询、部分匹配,就是从最左侧开始算,只要locate命令中的值在字段值当中存在就可以,不需要完全相等,例如对code字段进行查询,数据集的有三条记录,其中字段 code 的值如下:
00102
00103
00201
locate('code', '002', []);是查不到数据的
locate('code', '002', [loPartialKey]);是可以查到数据的
所以,如果你不需要模糊查询的时候,第三个参数,不要加 loPartialKey。
在中间层函数里,如果有类似下面这种代码,一定要先写SetAbort,再写Raise,就是说要先回滚事务,再抛出异常。
SetAbort;
Raise Exception.Create('打开分摊最高限价表“zd_charge_item_limit”异常:' + e.Message);
Exit;
通过appserver方式调用中间层函数的时候报错“无效的被呼叫方”
参数的in,out类型,或TLB定义的类型与你传入的参数类型不匹配,一般是中间层参数定义的类型是out,但是在客户端调用的时候使用了常量。
Raise 在中间层抛出异常给客户端,在客户端可以用
try
except
on E: Exception do
begin
showmessage(E.message);
end;
end
来捕获,这样就可以获取中间层抛出的错误信息。
报表参数问题,现在系统维护做报表的时候,参数最多支持到10位,如果再长,在给参数定义类型的时候会被截断,所以如果程序里的参数名字是超过10位的,系统维护又做不出超过10位参数名的报表,结果就是这报表废了。
Data Controls 控件组里的 DBRadioGroup 在数据集的前当记录变更的时候,如果关联字段的值改变,这个控件会自动触发OnChange事件,DBCheckBox 在相同的情况下,会自动触发单击事件OnClick,如果这两个控件的这两个事件里写过代码,需要注意这事,在数据集关闭、打开的时候,如果字段值改变也会触发这两个事件。
====以下内容未经过确认==========================
如果Delphi在编译的时候不该加点的地方加了编译蓝点,单步时乱走乱跳,可以把代码copy到记事本中,用纯文本查看,有可能有怪字符。
在安装中间层DLL时报TYPELIB无法加载,是由于DELPHI生成的DCOM不是标准的DCOM,必须要MIDAS。DLL来支持,必须在system32下COPY Midas.dll,再在COM+中安装DLL
在写SQL语句有UNION的地方请注意写UNION ALL,否则出来的结果莫名其妙,有时候正确,有时候不正确,不正确的数据即不是上部分的结果也不是下部分的结果,这一般出现在UNION中的一块没有结果集。
一预览报表,程序就消失,有可能的原因:本地没有安装打印机驱动
对COM+组件进行了调用,但是组件方法已被终止。
这是由于在SetAbort后没有写退出语句仍然往下执行,下面还有对数据库的操作,所以报错.
无效的索引。原因:中间层ADOQUERY定义的参数与客户端CLIENTDATASET的参数数量不一致。
分布式事务已完成,请将此会话登记到新的事务或Null事务中。原因:是SQL的参数是非法数据。例如需要一个日期参数,但是进去的是一个Float,转换不过去 ,就报错
仔细介绍入院录入的配置文件“InPatientInput.xml”
暂时关闭某个控件的事件响应,例如afterscroll
添加 fkInternalCalc 计算字段后, 打开记录集出错 name not unique in this context
除了有可能是dcomconnection的connected没有置为true之外,还有可能是老版本的中间层,这个函数根本不存在
关于savetofile
1.如果clientdataset 的active 为 false,则savetofile不会生成文件
2.如果clientdataset 的active 为 true,则savetofile会生成cds文件,如果clientdataset 里有数据,那生成的cds文件也会有数据,并且不受filter的影响(就是说如果clientdataset里是有数据的,即使filter导致当前的recordcount为0,savetofile生成的cds文件里也会有数据),如果clientdataset中没有数据,则生成的cds文件有结构,没有数据
在DBGridEh里,如果有字段在footer里计算合计,则关联数据集在open的时候,会自动遍历所有数据(触发afterscroll事件,相当于从头到尾循环一遍)
TDBCheckBox控件,在关联的字段赋值的时间会自动触发OnClick事件,如果不想触发,在关联的数据集赋值之前用 DisableControls ,关闭自动感知控件的响应就可以了。
录入控件相关的编码,如果需要扩位,有时会出现录入控件选择了新宽度的项目之后,不显示名称,编码尾部被截断的情况,这种现象的原因是中间层取了固定列,并且相关编码的位数比较小。
至少一个参数没有被指定值
1.录入控件中,如果有参数没有被赋值有可能会报这个错误
2.open的时候,数据集的入参有为null或没有赋值而且没有默认值的。
76. 确定程序中会执行SQL语句,但是在数据库上跟踪不到
1.查一下SQL Server Profiler是不是有筛选器
2.查一下数据库的连接,是不是指向另外的库了。
77. 浮点数比较的精度问题
在SQL SERVER数据库中,由于运算精度的原因,有时float类型的数据会出现把1存成0.9999999或1.00000001这样的数据,这样的数据在进行浮点数之间的比较尤其是相等比较时会出现误差,
例如下面这段代码:
procedure TForm1.Button1Click(Sender: TObject);
var
a,b: double;
begin
a := 2.0;
b := 1.99999999;
if a = b then
ShowMessage('相等')
else
ShowMessage('不相等');
end;
会弹出提示,“不相等”,如果比较的是金额,就会把本来相等的金额,误判成不相等。
解决方案1:
if Round(a * 100) = Round(b * 100) then
解决方案2:
if abs(a - b) < 0.001 then
78. Filter速度比较慢
1.有可能是数据集有index,去掉之后可以加快速度
更多推荐
一些常见的问题
发布评论