极度郁闷中... 求教:三层COM+(没用Midas)中,为什么我在Initialize中初始化的变量,在同一对象中,访问不了?

gub 2004-01-03 01:50:45
COM+三层,未使用Midas,使用的ADO原生对象。
其中一个Transactional Object: DBAgent. 用来访问数据库。

(一)
1.1 首先我定义了一个Private的Con: _Connection,
并在DBAgent的Initialize(overload)中,把它打开。
Con := CoConnection.Create;
ConStr := 'Provider=SQLOLEDB.1;Initial Catalog=DocuMan;Data Source=GUB';
Usr := 'sa';
Pwd := 'XX';
Con.Open(ConStr, Usr, Pwd, adConnectUnspecified);

1.2 然后,在我的一个接口方法中使用它。
procedure TDBAgent.GetRS(const aComTxt: WideString; var vRS: _Recordset);
begin
try
// vRS.Set_ActiveConnection(Con); //这句加不加 下场一样。

vRS.Open(aComTxt, Con, adOpenStatic, adLockBatchOptimistic, adCmdText);

SetComplete;
except
SetAbort;
end;
end;

1.3 在客户端,
procedure TForm1.Button1Click(Sender: TObject);
var
AgntObj: IDBAgent;
rs: _RecordSet;
begin
AgntObj:= CoDBAgent.Create;
rs := CoRecordSet.Create;
AgntObj.GetRS('Select * from T_Box',rs);
...
end;

下场:
客户端得不到Recordset.

(二)
2.1 直接在接口方法中指定ConStr
Constr := '连接字符串';
vRS.Open(aComTxt, Constr, adOpenStatic, adLockBatchOptimistic, adCmdText);

其他不变。

结果:
客户端可以得到RecordSet.

(三)
3.1 定义了一个Private(Protected/Public我也试了)的ConStr: string;
(为什么不用ResourceString? 因为我不想写死ConnectionString,我要从Registry中获得它)

3.2 分别在Initialize和OnActivate中,对它进行初始化。
Constr := '连接字符串';

3.3 把接口方法中对Constr 的赋值 一句去掉。

下场:
还是得不到RecordSet.

(四)
4.1 索性添加一个借口方法GetConStr返回 BSTR

4.2 分别在Initialize和OnActivate中,对它进行初始化。
Constr := '连接字符串';

4.3 客户端
procedure TForm1.Button1Click(Sender: TObject);
var
AgntObj: IDBAgent;
str: String;
begin
AgntObj := CoDBAgent.Create;
str := AgntObj.GetConStr;
...
end;

下场:
得不到ConStr的值。

(五)
极度郁闷。

(六)
求救!!!!!
...全文
97 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
eastliangliang 2004-01-12
  • 打赏
  • 举报
回复
用原生ADO呢?还是用转换XML?总结一下吧:)
gub 2004-01-12
  • 打赏
  • 举报
回复
问题基本解决。

谢谢苹果兄!
gub 2004-01-07
  • 打赏
  • 举报
回复
谢谢楼上!
我试试先。
eastliangliang 2004-01-06
  • 打赏
  • 举报
回复
简单写了个程序,没有出现楼主所说的情况。但是,我用的是Delphi的ADO控件:TADOConnection和TADOQuery。变量用的是OleVariant而不是直接用_Recordset,应该不是这个问题。
对ADO原生对象不熟,以前也碰到过得不到记录集的情况,那是在两个组件以上传递记录集时,我的解决办法是读出记录集后用ADO的方法转换成XML字符串,字符串总是可以传递的,然后传到最外面的组件后再还原成记录集,如果时间紧,可以先这样试试。

转换函数如下:
unit CCDBOperateUtils;

interface

uses
Windows, ADODB_TLB, MSXML2_TLB;

//transforms an ADO recordset to an XML doc
function RecordsetToXML (const Data: _Recordset): string;
//transforms an XML doc to an ADO recordset
function XMLToRecordset (const XML: string): Recordset;

implementation

uses
SysUtils {$IFNDEF D5_AND_BELOW}, Variants {$ENDIF}, Mtx, ComObj, Classes;
//Bookworm_TLB;

function RecordsetToXML (const Data: _Recordset): string;
var
stm: Stream;
begin
stm := CoStream.Create;
Data.Save (stm, adPersistXML);
Result := stm.ReadText (stm.Size);
stm.Close;
stm := nil;
end;

function XMLToRecordset (const XML: string): Recordset;
var
stm: Stream;
begin
Result := CoRecordset.Create;
Result.CursorLocation := adUseClient;
stm := CoStream.Create;
stm.Open (EmptyParam, adModeUnknown,
StreamOpenOptionsEnum(adOpenStreamUnspecified), '', '');
stm.WriteText (XML, stWriteChar);
stm.Position := 0;
Result.Open (stm, EmptyParam, CursorTypeEnum(adOpenUnspecified),
LockTypeEnum(adLockUnspecified), 0);
stm.Close;
stm := nil;
end;

end.
gub 2004-01-03
  • 打赏
  • 举报
回复
我只想定义一个Con在该对象内使用,而不想也不必要把它暴露给其他对象。
我这么做的原因有二:
1. 我认为Con的打开比较费时间。在对象建立时,我就把它打开。池化后,它仍然是打开的。
再次从池中取出来得时候,就省去了再次建立Con的时间。
2. 连接字符串的生成是灵活的(不是写死的,便于发布时设置)。在对象建立时,我生成连接字符串后,就不需要再去管它。

我确实对Com的原理不熟悉,刚刚关注它一个多月。
简单瞄了一下李维的ADO/MTS/COM+,就上路了。
前两天买了 COM原理与应用 等几本Com的书,可是时间紧,来不及仔细看了。
只好用到什么就去翻。

谢谢楼上的朋友,请继续指教。
biggo 2004-01-03
  • 打赏
  • 举报
回复
可能你对Com的原理还是不是很熟悉。如果你真的想定义一个公用的Con
你最好在服务端开个新的数据模版,在其中定义Con,在ini中初始化Con,
然后在接口中调用数据模版中的Con就不会出现问题了。

2,498

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 数据库相关
社区管理员
  • 数据库相关社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧