与CDS有关的一些杂其杂八的问题

cds理论

http://gang4415.blog.51cto.com/225775/273481

 

问题.500,难道用500DataSetProvider

回复:

1楼:是的,成对出现,除非你不是用DataSetProvider做连接的。不过一般要看ClientDataSet最多时会显示几个,DataSetProvider就有几个太多的话,可以动态创建,TList管理。

2楼:可以只用一个。使用通用的参数,比如参数1指定库名,参数2指明表的名字,参数3编码组合实际的参数。中间层解包后在querybeforeopen事件里动态生成相应的sql语句。我们公司采用的也是这种方案。

2. Delphi做三层开发时,很多人都会在客户端放一个TClientDataSet,中间层远程数据模块就对应放一个TDataSetProvider, 然后再连起来.其实这种方法很烦琐,而且程序痈肿不甘,不好维护.我们都知道TClientDataSetDelta属性记录了数据的所有修改,应用它 我们就可以方便的实现一个单表更新的通用方法.

回复: 

中间层添加一个通用的更新方法,就叫ApplyUpdates

方法定义如下: function ApplyUpdates(const UpdateTable:String;Delta:Variant;out err:String):Boolean;

参数UpdateTable是指要更新的表名,Delta是指传过来的TClientDataSetDelta属性,如果更新错误err返回错误的内 容(实现这个方法思路,DataModule上放一个TdataSetProvider—Query--Connection首先开始一个事物Conn.BeginTrans;

 格式化语句填入表名:sqlstr:=Format('select * from %s where 1=0',[UpdateTable])后传入Query打开,取得这个表的表结构。提交修改的数据Provider.ApplyUpdates(Delta,-1,ErrCount);并对Reuslt赋值Result:=ErrCount=0;根据Reuslt判断事物是提交还是回滚。)

 

到此,通用的更新方法已经完成了.不过客户端的ClientDataSet还不能查询显示数据,因此,还要写一个查询方法:

??? function QuerySQL(const sqlstr:string;out Data:Variant;out err:String):Boolean;

??? 参数sqlstr就是要持行的查询语句,Data返回查询结果,错误时err返回错误消息

到这里,中间层的代码已经完了,客户端的调用就简单了.比如客户端有个数据模块DM,上面放一个DcomConnection或者 SocketConnection,名叫Conn.客户端上增删改完后,这时的数据还在客户端的内存里,想保存到远程的中间层服务器就要用到我们刚才的方法了比如

var err:string;

begin

 if cds.ChangeCount=0 then exit;//数据没改变就不用提交了;

   if Dm.Conn.AppServer.ApplyUpdates('xxx',cds.Delta,err) then//xxx就是表名了

?    cds.MergeChangeLog;//合并所有改变的数据

   end else MessageBox(self.handle,pchar('保存出错:'+err),'错误',MB_OK+MB_ICONERROR);

end;

到此,这篇文章也讲完了.用这个方法,那些单表的基础数据更新还可以写成一个祖先类,只要加一个取得更新表名的虚方法,比如:function TableName:string;virtual;然后其后代只要override这个方法,返回各自的表名,其他的一句代码都不用写.

有个小问题是,这个表的主键的生成问题,这里我们不能用自增主键,要自己自己生成主键,这样你还得在中间层写一个中间层生成主键的方法,

问题

慎用TclientDataSet.Data, 当我们调用cdsxxx.data := anyData,它会把值赋给FSavedPacket。所以此时FSavedPacket已经<>nil了,而且从源码上看,TClientDatasetclose的时候并没有把FSavedPacket清掉。所以下次Open的时候,其实这个Open是不会去取数据的。

解决这个问题的办法是自己派生一个新的ClientDataset

TMyClientDataSet = class(TClientDataset)

protected

?? procedure CloseCursor; override;?

TMyClientDataSet.CloseCursor;

begin

? inherited CloseCursor;

? Data := null; //此处清空FSavedPacket

end;

问题:TClientDataSet加上TDataSetProvider的数据保存问题?

前台:D7D2005; DBExpress连接组件: ?TSqlConnection,TSqlQuery ,TDataSetProvider,TClientDataSet;

后台:SQLServer2000

更新数据的命令:DataSetProvider.ApplyUpdates(ClientDataSet.Delta , -1 , ErrorCount);

设置DataSetProvider.ResolvetoDataSet:= True,用以触发BeforeUpdateRecord事件处理函数更新数据的命令写在BeforeUpdateRecord事件中。问题: 1新数据前必须要断开连接,否则就有可能出错。错误的提示意思是不能再开启事务了,其实根本就没有手动开启事务,只有BeforeUpdateRecord自动开启的事务。2因为更新每一个ClientDataSet之前都要断开连接,因此更新多个ClientDataSet时无法进行事务处理。

TDBGrid->TDataSource->TClientDataSet->TDataSetProvider->TSQLQuery->TSQLConncetion

要知道,TClientDataSetCommandText属性是不可写的,要变换不同的SQL语句进行查询,就修改TSQLQuerySQL.Text属性,然后用TClientDataSetOpen方法执行SQL语句。

ClientDataSet在设计时add all fields

问题:一直以来字典类数据都是用DBExpress+ClientDataSet来出来的.但知道最近才发现在处理SQL SERVER2000数据库时对字符型字段,保存的数据末尾有'\0'(ASCII 0)的存在.也就是说,如果保存的是'ABCD',那么实际数据库字段长度不是4,而是5.这个问题该如何解决呢?不是空格,所以trim无效.实际上我测试过ClientDataSet.Filed[n].AsString的长度,是正常的.只是提交数据库后才出问题.

回复:经测试,DBExpress的数据驱动程序有关.连接ORACLE时没有该问题,改用ADO连接SQLSERVER也没有该问题.

问题:如何获得ClientDataSet执行的SQL语句。

回复:SQL语句不是由ClientDataSet解悉的,可能是由DataSetProvider解悉,也可能是由ADO解悉,前者应该可以取得,后者就难了.但这些都是在ApplyUpdates后发生的,不過你可以DataSetProvider1BeforeUpdateRecord(Sender: ? TObject;?

? ? SourceDS: ? TDataSet; ? DeltaDS: ? TCustomClientDataSet;?UpdateKind: ? TUpdateKind; ? var ? Applied: ? Boolean);這個事件里?DeltaDS來看個個字段的值﹐以及各種狀態啊

问题:

利用Adoquery ? ,clientdataset ? ,datasetprovidor ? 更新?

datasetprovidor ? 設置?

resolvetodataset ? =true;?

updatemode ? =upwhereall?

Adoquery ? 設置?

cursorlocation ? =cluseclient?

cursortype ? =ctstatic?

locktype ? =ltbatchoptmistic ? or ? / ? ltoptmistic?

以前post ? ,applyupdates(-1),有時正常,有時出現,record ? not ? found ? ? or ? change ? by ? another ? user ? 就裝了個D6_UPD2_EN.EXE,ADO26_TRA.exe?

clientdataset中有一自動增長id ? (sql ? server ? table ? A ? ? id是主關鍵字) ? 再數據更新applyupdates(-1),applyupdates(-1)出現key ? violation ? 錯誤信息!,單單自動post也出現key ? violation ? 錯誤信息!,?

但另做一個PROJECT ? 利用Adoquery ? ,clientdataset ? ,datasetprovidor,同樣設置, ? applyupdates(0)又成功更新,id自動增長,怎麼解決!請大家幫幫手,謝謝?

回复:自增量字段你是不用作处理的,你在新增时不要显式的对该字段设值,那是数据库作的工作。

提问:我用 ? SQLConnection-> DataSetProvider-> ClientDataSet ? 的结构连接IB数据库,在程序里面给ClientDataSet-> CommandText赋值再Open,就会发生异常,说是“CommandText ? changes ? are ? not ? allowed”。不知道是为什么,高手指点一下啦

回复:DataSetProviderOptions属性里,poAllowCommandText值要为true

问题:执行ClientDataSet1.Append ? 添加完数据后,保存的时候就出现“Record ? not ? found ? or ? changed ? by ? another ? user”的错误,应当如何解决??保存的代码为: ? ClientDataSet1.ApplyUpdates(-1);

回复:ClientDataSet应用更新时,服务端控件先要检索该记录:select ? * ? from ? 表名 ? where ? 字段1= '更新前内容 ' ? and ? 字段2= '更新前内容 ' ? and ? 字段3= '更新前内容 ' ? and ? …… ? ? 所有字段都作为条件。?

该错误出现的情况有:?

1、该记录在提交更新时被他人修改过?

2、字段中有长日期类型?

解决方法:?

不用ClientDataSet更新,通过SQL语句更新或者设置服务端的控件的字段属性,把主键字段的ProviderFlagspfinKey属性设为true,这样ClientDataSet更新时服务端检索记录时的条件仅包含该字段而不是所有字段?

当然,这样的话如果在提交之前该记录被他人修改过(不改主键字段)的话,你仍可更新该记录,而不会有你看到的错误提示。

问题:我想清空内存里的数据,用的是 ? clientdataset.close ??帮助里说.close是切断客户端与服务器端的联系而已;?有什么办法可以切断他们的联系,并且清空内存的数据呢?

回复:clientdataset.freedata?我记得好像有这个;请问FREEDATA执行的时机??好像是EMPTYDATA

ClientDataSet字段不能进行编辑时的解决方法

ClientDataSet字段不能进行编辑时的解决方法:

procedure ModifyClientDataSet(const YesOrNot: Boolean;

? cs : TClientDataSet);

var

? i : Integer;

begin

? // 当 YesOrNot 为 true 时为只读false 是可进行修改

? for i := 0 to cs.FieldCount -1 do

? begin

??? cs.Fields[i].ReadOnly := YesOrNot;

? end;

end;

ClientDataSet 所对应的不是真实存在的字段时,就会出现不能进行编辑的情况。

比如是通过 '' as 字段1 , 这时 字段在运行时是不能编辑的。

?如果ClientDataSet是能过动态创建的,或都是assigned其他的ClientDataSet的结构,

需要在 ClientDataSet.CreateDataSet 之后再调用此方法

ClientDataSet控键的动态 Assign Local Data 解决方案

在设计模式下,可以用鼠标右键Assign Local Data加载Table或者Query数据,

但在代码里实现却无从下手. Google了一段时间,找到一个解决办法.

1. var??

2. ??pv:TProvider;??

3. begin??

4. ??pv:=TProvider.Create(nil);??

5. ??pv.DataSet:=adoquery1;??

6. ??ClientDataSet1.Data:=pv.Data;??

7. ??freeandnil(pv);??

8. end;?

Raptor的一点补充:?

其一,在三层结构中使用SQL,违背了三层结构的宗旨,不如回家去用两层。?

其二,与其瞎猜,不如实际动手证实一下,如果你使用的数据库是SQL ? SERVER,那么使用事件跟踪器一目了然。?

其三,我同意使用upWhereKey,但其实根本不需要自己去设,当然做法需要不一样,原理是这样从数据集的元数据中

? ? ? ? ? ? 可以完全知道,何必多此一举

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值