为什么我的客户端不能显示远程数据库查询的数据?(100分)

  • 主题发起人 soFTangeL
  • 开始时间
S

soFTangeL

Unregistered / Unconfirmed
GUEST, unregistred user!
远程数据模块YXSF_DM中的查询用户方法定义如下:
procedure TYXSF_Server.FindUser(Sqlstr: OleVariant);
begin
Query.Close;
Query.SQL.Clear;
Query.SQL.Add(sqlStr);
Query.Open;
end;

客户端这样调用:
procedure TClientFindUser.Button1Click(Sender: TObject);
var
sqlstr:string;
begin
SqlStr:='select * from User where UserNum='''+UserNum.Text+'''';//生成查询语句
ClientFindUserResult:=TClientFindUserResult.Create(Application);
Try
ClientForm.DCOMConnection.AppServer.FindUser(Sqlstr);
//调用远程数据模块 YXSF_DM中 的 FindUser 方法
ClientFindUserResult.Showmodal;
//调出查询结果窗口
Finally
ClientFindUserResult.Free;
end;
end;

我可以保证查询语句是绝对正确的。我已经跟踪验证。如果换成 DELETE 或 INSERT 语句完全可以正常运行。只有查询语句不能正常运行(给我的感觉是能正常运行,只是结果无法在客户端显示而已。参数SqlStr能正常赋给 FindUser(Sqlstr))结果使用 GBGrid显示。经测试连接正常。
按说能正常显示的,但他就是不显示。诸位帮我看看是怎么回事?小小100分敬上,不成敬意。还望笑纳。谢谢!
 
怀疑你的clietdatset的providername无设置好
另外procedure TYXSF_Server.FindUser(Sqlstr: OleVariant);是你直接在代码加入,还是在
view----->type library 建立的先?
如果是前者,是不行的,没有注册,应该采用后者的方法。
 
这个问题我也遇到过。首先你要在客户端的相应函数中建立一个OLEVARIANT的变量
具体如下:
客户端这样调用:
procedure TClientFindUser.Button1Click(Sender: TObject);
var
sqlstr:string;
s: OleVariant;
begin
SqlStr:='select * from User where UserNum='''+UserNum.Text+'''';//生成查询语句
s:=sqlstr;
ClientFindUserResult:=TClientFindUserResult.Create(Application);
Try
ClientForm.DCOMConnection.AppServer.FindUser(s);
//调用远程数据模块 YXSF_DM中 的 FindUser 方法
ClientFindUserResult.Showmodal;
//调出查询结果窗口
Finally
ClientFindUserResult.Free;
end;
end;
 
楼主的例子我看明白了:
你是想通过在客户端直接更换中间层的Query中的SQL语句,以达到复用中间层组件
的目的?
1、首先这种用法是不对的。进行3层程序设计时,最需要避免的就是在客户端直接写SQL。
2、产生问题的原因是:
ClientForm.DCOMConnection.AppServer.FindUser(Sqlstr)
程序在这一句时,通过DCOM的调用产生的一个中间层的COM,称为A;
估计在你的ClientForm中有一个ClientDataSet 和中间层的Query相连,
这个ClientDataSet的Open动作将在中间层激活另外一个COM,称为B;
A <> B,这是由于COM的机制决定的,每个客户端的请求将产生与之对应的独立的
COM来进行相应。
3、如果确实是我说的问题,我再写上解决方法
 
To delphilove:谢谢你的提醒,不过我的确是用 view----->type library 这样的方法建立的语句。
To ieiszwxm:这个方法我试了,还是不行。我怀疑是三楼 weic 所说的问题。不过还是要谢谢您提供的解答。
To weic:我估计就是您所说的问题。我的确是“在你的ClientForm中有一个ClientDataSet 和中间层的Query相连”,您能把
解决方法写出来么?谢谢!
 
如果确实如此,楼主不妨这样考虑:
换SQL和取数能不能同步进行?
因为你的Query一定有一个DataetProvider和它相连,当你的函数执行到
.......
Query.Open;
^^^^^这句执行结束时,DataSetProvider的Data属性已经包含了,你需要的结果。
end;

所以可以把中间层的函数修改如下:
function TYXSF_Server.FindUser(Sqlstr: OleVariant): OleVaraint;
begin
Query.Close;
Query.SQL.Clear;
Query.SQL.Add(sqlStr);
Query.Open;
if Query.RecordCount > 0 then
Result := DataSetProvider1.Data
else
Result := Null;
end;
在客户端接到这个数据集之后,在决定如何将其传递到ClientForm中。
 
对于客户端动态调用存储过程我用的是如 weic 的方法实现了
但在客户端动态执行SQL语句时,我没有这么作,而是通过 commandText传语句到服务器并执行
,如果有参数的话就建立参数,服务器端没作什么,只是dsp和ADOQuery相联。
//客户端动态SQL语句如下
procedure TfrmExample.btnADOClick(Sender: TObject);
begin
with cdsADOdo
begin
if Active then
Close;
CommandText := memo1.Lines.Text;
Params.Clear;
Params.CreateParam( ftString, 'c_exchange', ptInput);
Params.ParamByName( 'c_exchange').AsString := edtParam.Text;
Open;
end;
end;

这样都可以获得正确的结果。多个窗的ClientDataSet共用dsp显示数据也者没问题。
但现在我仍有疑问,因为程序中会有多个窗体同时开打,它们会共用一个DataSetProvider,
当客户端的ClientDataSet要更新数据调用ApplyUpdates()时,就有可能发生冲突。
我现在认为是:在ApplyUpdates()之前,ClientDataSet的commandText已经发生过变化,
因此它与它相连的DataSet也发生了变化,从而不能正确更新到数据库。
一个ClientDataSet与一个DataSetProvider对应是最安全的方法,但对于动态的SQL却比较麻烦,
可能要动态创建DataSetProvider…
不知 weic 有什么好的办法可以供大家学习一下!
 
to kingbc:我没有确定的是,你所说的DataSetprovider是放置在中间层还是客户端?
如果是中间层,就不会有共用的问题了。因为不论有多少个客户端联上来,COM都会创建
一个新的COM来给客户端使用。就算同时打开多个客户端窗体,每个Clientdataset相连
的Datasetprovider也是不同的
 
to kingbc:刚才没说完。呵呵,
实际上我没有好办法来解决动态换SQL的方法。在原来用PB开发的时候,写SQL、换SQL
似乎是非常方便的实用技巧。但是转向三层开发后,更多的是考虑如何将业务组件和
数据交换组件之间的衔接做的更灵活。
将SQL全部放置在数据交换组件当中,并对其进行功能性的分类。
简单的说,就是将所有可能用到的数据访问都做出来,然后在项目实施和维护的过程中
不断的丰富数据访问组件的数量。
只有这样才能最终实现组件工厂的目标。
 
听教,请搂上的先生慢慢讲来,学生洗耳恭听!
 
初来乍到,学习
 
中间层的函数修改如下:
function TYXSF_Server.FindUser(Sqlstr: OleVariant): OleVaraint;
begin
Query.Close;
Query.SQL.Clear;
Query.SQL.Add(sqlStr);
Query.Open;
if Query.RecordCount > 0 then
Result := DataSetProvider1.Data
else
Result := Null;
end;

似乎少了什么声明,编译不通过。:(
 
>>似乎少了什么声明,编译不通过。:(
能说明一下吗?什么错误?
 
不好意思,这几天有事。编译错误有错如下:
[Error] YXSF_DM.pas(170): Undeclared identifier: 'Null'
[Fatal Error] Server.dpr(22): Could not compile used unit '../unit/YXSF_DM.pas'
是不是我应该在YXSF_DM.pas对应的*.TLB中的函数声明改动些什么?应该怎样声明?
 
呵呵,昨天上不了DFW。
不是什么大问题,
在USES 单元中加入:Variants这个单元就行了,你用的一定是Delphi6吧
 
多谢!问题已解决!稍后即给分!
另:我用的正是 Delphi6 ,难道这是 delphi6 的“特性”?
 
只有在Delphi6中才有Variants这个单元,
把Null放在了这里
 
[8D]谢谢各位关注此问题的兄弟。并特别感谢 [red]weic[/red] 兄,您的解答另我又学到了一些知识。再次表示感谢![8D]
 
顶部