DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: li739139899
今日帖子: 7
在线用户: 5
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 12:23:12
标题:
datasnap服务器端如何更新多个fdmemtable 浏览:512
加入我的收藏
楼主: 请教大家,

datasnap服务器端如何更新多个fdmemtable?
----------------------------------------------
-把学习当信仰
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/11 12:55:16
1楼: 问题描述不清,罚款 500万人民币。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 14:23:46
2楼: 客户端传给服务器两个对象(用的fdmemtable),要求在服务器端事务性更新,如何处理?
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 15:34:04
3楼: 哪位老铁帮忙指点一二?
----------------------------------------------
-把学习当信仰
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/11 15:56:19
4楼: 客户端的 对象能传给服务器?
你牛啊。
我只知道传数据,比如 ZIP JSON BASE64 等 字节流。
其他的一律不会。

看来我水平太低了。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 grjs_2004 (grjsITname) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 16:21:59
5楼: 将TFDMemTable存入一个List(方法:List.AddObject('TableName1;Key1',FDMemTable1);多个Table则循环使用),然后再将List转成流上传服务器端。

服务器接收这个流,转成List对象装载下来,然后循环这个已经装载好的List取Object数据包,之后的动作,要看自己需要的控制逻辑进行处理了......
----------------------------------------------
Everyone will to do best!
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/11 17:03:17
6楼: 楼上牛人啊。
这就是说。
把一个地方的人名写入一张纸,然后 邮件发给 你,你就能把这些人 还原出来了?

为啥我只把这些人的 原子状态写入 一个超级大硬盘,发硬盘给对方,对方才能用 物质打印机,打印出来呢。

具体原理,请看 星际之门。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 17:06:22
6楼: 感谢楼上的建议,一会试下

试过几个方法,一直想找个简单点的

1.咏南的多表更新事务通用方法

发现不支持fdmemtable的delta,提示unsupported variant type '000D'

2.把delta转成sql,再在服务器上批量运行

这个方法应该不错,但发现有时fdmemtable会没有detal,cacheupdate也设置成trueb了,正在排查


3.第三种 是在客户端把fdmemtable savetostream,在服务端利用schemaapdater更新,待试
----------------------------------------------
-把学习当信仰
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/11 17:59:18
7楼: fdmemtable 可以 save ,那么就可以 load 啊。
服务器 的 处理函数,自己建一个 fdmemtable 或者 datamodule 里头放一个。
就可以 load 了啊。
然后 我一般用 
FDQuery 打开服务器上的表。
然后 FDQuery.copy 从 FdMemTable 复制内容过去。
数据库,就更新完成了。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/11 18:00:49
8楼: 从服务器获取数据也是一样的。
服务器 FDQuery save 一个流。
我客户端 FdMemTable Load 这个流,是打开了服务器的数据啊。
多简单的事情。

表结构都一模一样的。

听说 ORM 讨厌我这种做法。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 hnxxcxg (咏南中间件) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 18:03:38
9楼: 支持D6及以上版本,支持跨平台,支持任意表数量,支持基本数据类型,文件、图片、数据集、结构体。。。。。。的序列和还原,各种类型序列任意批组合。
procedure TForm1.btnPostClick(Sender: TObject);
// 多表 提交
begin
  Self.ConnectServer;
  var serial: TynSerial := TynSerial.Create;
  var m: TServerMethods1Client := TServerMethods1Client.Create(SQLConnection1.DBXConnection);
  try
    serial.WriteInteger('count', 2);          // 表的数量
    serial.WriteString('accountno', '1');          // 数据库帐套号
    serial.WriteString('tablename', 'tgoods');     // 表名一
    serial.WriteString('tablename2', 'tunit');     // 表名二
    serial.WriteFDDelta('delta', FDMemTable1);     // 修改数据一
    serial.WriteFDDelta('delta2', FDMemTable2);    // 修改数据二
    if m.Save99(serial.Text) then          // 调用远程接口
      ShowMessage('数据提交成功')
    else
      ShowMessage('数据提交失败');
  finally
    serial.DisposeOf;
    m.DisposeOf;
    SQLConnection1.Close;
  end;
end;

procedure TForm1.btnQueryClick(Sender: TObject);
// 多表 查询
begin
  Self.ConnectServer;
  var serial: TynSerial := TynSerial.Create;
  var m: TServerMethods1Client := TServerMethods1Client.Create(SQLConnection1.DBXConnection);
  try
    serial.WriteInteger('count', 2);          // 表的数量
    serial.WriteString('accountno', '1');          // 数据库帐套号
    serial.WriteString('sql', 'select * from tgoods');       // 查询语句一
    serial.WriteString('sql2', 'select * from tunit');       // 查询语句二
    serial.Text := m.Query99(serial.Text);          // 调用远程接口
    serial.ReadFDDataSet('dataset', FDMemTable1);          // 主表
    serial.ReadFDDataSet('dataset2', FDMemTable2);          // 从表
  finally
    serial.DisposeOf;
    m.DisposeOf;
    SQLConnection1.Close;
  end;
end;
----------------------------------------------
咏南中间件 QQ:254072148http://www.cnblogs.com/hnxxcxg/
作者:
男 hnxxcxg (咏南中间件) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 18:08:24
10楼: 序列、还原接口:   
   procedure WriteString(const key, value: string);
    procedure WriteInteger(const key: string; value: integer);
    procedure WriteFloat(const key: string; value: Double);
    procedure WriteBool(const key: string; value: Boolean);
    procedure WriteDate(const key: string; value: TDateTime);
    procedure WriteTime(const key: string; value: TDateTime);
    procedure WriteDateTime(const key: string; value: TDateTime);
    procedure WriteStream(const key: string; value: TStream);
    procedure WriteBuf(const key: string; const buf; const len: integer);
    procedure WriteBytes(const key: string; const bytes: TBytes);
    procedure WriteStringList(const key: string; const list: TStringList);
    procedure WriteFile(const key, filename: string);
    procedure WriteSerial(const key: string; serial: TynSerial);
    {$IFDEF fd}
    procedure WriteFDDataSet(const key: string; dataset: TFDAdaptedDataSet);
    procedure WriteFDDelta(const key: string; dataset: TFDAdaptedDataSet);
    function FDDeltaToString(dataset: TFDAdaptedDataSet): string;
    {$ENDIF}
    {$IFDEF ole}
    procedure WriteOleVariant(const key: string; ole: OleVariant);
    procedure WriteDelta(const key: string; cds: TClientDataSet);
    procedure WriteParams(const key: string; params: TParams);
    {$ENDIF}
    //----------
    function ReadString(const key: string): string;
    function ReadInteger(const key: string): Integer;
    function ReadFloat(const key: string): Double;
    function ReadBool(const key: string): Boolean;
    function ReadDate(const key: string): TDateTime;
    function ReadTime(const key: string): TDateTime;
    function ReadDateTime(const key: string): TDateTime;
    procedure ReadStream(const key: string; value: TStream);
    procedure ReadBuf(const key: string; var buf);
    procedure ReadBytes(const key: string; var bytes: TBytes);
    procedure ReadStringList(const key: string; var list: TStringList);
    procedure ReadFile(const key: string; stream: TStream);
    function ReadSerial(const key: string): TynSerial;
    {$IFDEF fd}
    procedure ReadFDDataSet(const key: string; dataset: TFDMemTable);
    procedure ReadFDDelta(const key: string; stream: TStream);
    {$ENDIF}
    {$IFDEF ole}
    function ReadOleVariant(const key: string): OleVariant;
    procedure ReadClientDataSet(const key: string; cds: TClientDataSet);
    procedure ReadParams(const key: string; params: TParams);
    {$ENDIF}
----------------------------------------------
咏南中间件 QQ:254072148http://www.cnblogs.com/hnxxcxg/
作者:
男 grjs_2004 (grjsITname) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 18:16:33
10楼: 6楼的先生,你没有理解好就乱下结论。

具体方法我没有写得很清楚,我是认为你们都很牛,一点就透的前提下这样留言的。
数据装载方法:
List.AddObject('TableName1;Key1',FDMemTable1);

呵呵~~~,字符串是用来指定表名和主键名用的,数据包是对应的TObject,这里是FDMemTable1

服务器端取数据包方法:
for i := 0 to List.Count-1 do
  fDQuery.CopyDataSet(TFDQuery(List.Objects[i]));

其它的自己去搞定
----------------------------------------------
Everyone will to do best!
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 18:19:02
10楼: 感谢楼上

我还是想用传统的方法 

我有10个表需要一次更新,要么成功,要么失败

如何把10个tmemorystream传给服务器,如何序列化?tlist,tobjectlist都没有提供savetostream方法
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 18:20:09
11楼: @grjs_2004,
如何序列化这个list?
----------------------------------------------
-把学习当信仰
作者:
男 grjs_2004 (grjsITname) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 18:22:20
11楼: 只要是TObject,都可以转为Stream
----------------------------------------------
Everyone will to do best!
作者:
男 hnxxcxg (咏南中间件) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 18:24:50
12楼: 在中间件的远程方法里面进行事务控制,10个表的提交数据,要么都成功,要么都回滚。
----------------------------------------------
咏南中间件 QQ:254072148http://www.cnblogs.com/hnxxcxg/
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 18:40:24
13楼: 现在是不知道怎么把这10个memorystream传到中间层,放到tlist里,要怎么序列化?
放到tstringlist里是不是也可以,tstringlist有savetostream方法
----------------------------------------------
-把学习当信仰
作者:
男 hnxxcxg (咏南中间件) ★☆☆☆☆ -
盒子活跃会员
2019/4/11 18:43:20
14楼: CLIENT 十个MemoryStream可以合并为一个MemoryStream
SERVER 一个MemoryStream可以分解为十个MemoryStream
----------------------------------------------
咏南中间件 QQ:254072148http://www.cnblogs.com/hnxxcxg/
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 18:53:54
15楼: 咋整?咏南
----------------------------------------------
-把学习当信仰
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2019/4/11 19:02:35
16楼: 别用datasnap ,用datasnap REST,使用FDJsonDataSet和JsonArray传递数据。
多个FDMemtable与单个更新,没有区别,与vcl差不多。
----------------------------------------------
-
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 19:09:05
17楼: 现在项目已经用了fdmemtable + datasnap + stream传递数据,改来不及
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 19:18:18
18楼: datasnap 不接受TList<Tmemorystream>作入参,提示invaild variant type  conversion
----------------------------------------------
-把学习当信仰
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2019/4/11 19:18:31
18楼: datasnap如果使用tcp/ip通信,长连接管理麻烦,而且datasnap使用流,即使使用最新版本仍有bug,有后患。
datasnap rest使用http通信,是emb主推的中间件设计方式,我在项目中使用很好,既可以stream亦可用json交换数据。
----------------------------------------------
-
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 19:19:28
19楼: 蛋碎一地,求救
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 19:20:53
20楼: 来不及了,惊云兄
----------------------------------------------
-把学习当信仰
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2019/4/11 19:24:23
21楼: datasnap rest并发数也优于datasnap,目前用datasnap开发,可能没有实用性。当然,听不听由你,其实改成datasnap rest,工作量并不大,主要的业务逻辑并不须改动,只是连接换一下而已。
----------------------------------------------
-
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 19:29:36
22楼: datasnap搞了这么多年,没有多表更新的成熟方案?

@sxqwhxq (步惊云)

rest 跟fdmemtable之间转换数据麻不麻烦?
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 19:45:31
23楼: datasnap 不支持 VarArrayOf传参
----------------------------------------------
-把学习当信仰
作者:
男 nickemma (N.E) ▲▲▲▲△ -
注册会员
2019/4/11 20:39:08
24楼: 办法多的是。

上面提出的用Delta生成SQL语句,多个Delta SQL语句传到服务端,然后事务更新。亦可客户端对多个Delta合并SQL语句,传到服务端更新。
至于你说的FireDAC的组件的Delta有时候没有,这个情况我没出现过,或许你不会用而已。

另外我个人是不建议客户端生成SQL语句,不安全之余还多个转换动作,既然你知道Delta可以保存为流,传输流及服务端用Load流来更新。那样你可以把多个Delta流生成为一个流,到服务器再解包更新(其实就是定位读取流而已)。
----------------------------------------------
-
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/11 21:21:02
25楼: 对流操作不太熟,不知道怎么合并及合并后怎么取,合并的话应该要把每个流的起始位置与大小记录下来一并发到服务端吧,感觉复杂些,现在比较倾向于在客户端生成sql然后传到服务端去执行,会有点风险,但是胜在不复杂,黔驴呀
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 7:34:06
26楼: 在stringlist中addobject一个流对象,然后把这个stringlist 保存成一个流发给服务端,在服务端创建一个stringlist对象,然后loadfromstream从客户端传过来的流,发现addobject的流为nil了,什么毛病
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 7:44:03
27楼: https://groups.google.com/forum/#!topic/borland.public.delphi.vcl.components.using.win32/qSIdOjCHfZA 

http://delphi.ktop.com.tw/board.php?cid=30&fid=70&tid=47724

看来在stringlist中保存对象也不太容易
----------------------------------------------
-把学习当信仰
作者:
男 joman (joman) ▲▲▲△△ -
注册会员
2019/4/12 7:57:32
26楼: 组装一个json数组 直接post到 http服务不就好了
----------------------------------------------
DelphiWebMVC官网 http://www.delphiwebmvc.com
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 8:05:38
28楼: 搞成sql文本?二进制的东西怎么变json
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 8:06:13
29楼: 哪位老铁有参考的代码,时间紧
----------------------------------------------
-把学习当信仰
作者:
男 feiyanm (feiyanm) ▲▲▲△△ -
注册会员
2019/4/12 8:12:28
28楼: 建议楼主还是多学习学习基础知识吧,否则看到大家都在对牛弹琴,挺尴尬的,你尴尬的是这是什么弱鸡玩意儿?大家尴尬的是sujgcdvbjhhdfvddugcdfjh。。看着很着急。。。。
----------------------------------------------
Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!Delphi威武!千秋万代,一统江湖!我去WC吐一会儿去!
作者:
男 ksrsoft (cb168) ★☆☆☆☆ -
注册会员
2019/4/12 8:26:22
30楼: datasnap rest http
----------------------------------------------
-
作者:
男 sbipyps (sb) ▲▲▲▲▲ -
普通会员
2019/4/12 9:17:26
31楼: Delta组织SQL

客户端
sSql := 'begin tran;';
if cdsMain.ChangeCount > 0 then
begin
  sSql := sSql + ';' + SMC.GetSqlFromDelta(MainTableName, KeyID, cdsMain.Delta);
end;

for i := 0 to Details.Count - 1 do
begin
  if TClientDataSet(Details[i].DataSet).ChangeCount > 0 then
     sSql := sSql + ';' + SMC.GetSqlFromDelta(Details[i].tablename, Details[i].keyfield, TClientDataSet(Details[i].DataSet).Delta);
end;
sSql := sSql + ' if @@error <> 0 rollback tran else commit tran';

SMC.ExecuteSql(sSql, false);

cdsMain.MergeChangeLog;
for i := 0 to Details.Count - 1 do
begin
   TClientDataSet(Details[i].DataSet).MergeChangeLog;
end;

服务端
function TServerMethods1.GetSqlFromDelta(aTableName: string; aKeyFields: string; aDelta: OleVariant): string;
var
  i: Integer;
  cdsupdate: TClientDataSet;
  sql: string;
  supdate: string;
  sfields: string;

  sl: TStringList;
  slKeyFields: TDictionary<string, string>;

  scondition: string;
begin
  try
    sql := '';

    sl := TStringList.Create;
    sl.Delimiter := ';';
    sl.DelimitedText := aKeyFields;
    slKeyFields := TDictionary<string, string>.Create;

    for i := 0 to sl.Count - 1 do
      slKeyFields.Add(sl[i], '');


    cdsupdate := TClientDataSet.Create(nil);
    cdsupdate.Data := aDelta;
    cdsupdate.First;
    while not cdsupdate.Eof do
    begin
      //////////
      if not cdsupdate.FieldByName(sl[0]).IsNull then
      begin
        for i := 0 to sl.Count - 1 do
        begin
          if slKeyFields.ContainsKey(sl[i]) then
          begin
          slKeyFields[sl[i]] := cdsupdate.FieldByName(sl[i]).AsString;
          end;
        end;
      end;
      //////////
      case cdsupdate.UpdateStatus of
      usInserted:
        begin
          sfields := '';
          for I := 0 to cdsupdate.FieldCount - 1 do
          begin
          if GetTableFields(aTableName).IndexOf(cdsupdate.Fields[i].FieldName) <> -1 then
          sfields := sfields + cdsupdate.Fields[i].FieldName + ',';
          end;
          Delete(sfields, Length(sfields), 1);

          sql := sql + ' insert into '+ aTableName +' (' + sfields  +') values (';

          for i := 0 to cdsupdate.FieldCount - 1 do
          begin
          if GetTableFields(aTableName).IndexOf(cdsupdate.Fields[i].FieldName) <> -1 then
          begin
          case cdsupdate.Fields[i].DataType of
          ftAutoInc, ftByte, ftShortint, ftSmallint, ftInteger, ftWord, ftLongWord:
          begin
          if (not cdsupdate.Fields[i].IsNull) then
          sql := sql + IntToStr(cdsupdate.Fields[i].value) + ','
          else
          sql := sql + 'Null' + ',';
          end;
          ftFloat, ftSingle, ftCurrency, ftBCD, ftFMTBcd, ftExtended:
          begin
          if (not cdsupdate.Fields[i].IsNull) then
          sql := sql + FloatToStr(cdsupdate.Fields[i].value) + ','
          else
          sql := sql + 'Null' + ',';
          end;
          ftString,ftWideString, ftFixedChar, ftFixedWideChar:
          begin
          if not cdsupdate.Fields[i].IsNull then
          sql := sql + Quotedstr(VarToStr(cdsupdate.Fields[i].value)) + ','
          else
          sql := sql + 'Null' + ',';
          end;
          ftDate, ftTime, ftDateTime, ftTimeStamp:
          begin
          if not cdsupdate.Fields[i].IsNull then
          begin
          sql := sql + QuotedStr(Formatdatetime('yyyy-mm-dd hh:mm:ss', vartodatetime(cdsupdate.fields[i].value))) + ','
          end
          else
          sql := sql + 'Null' + ',';
          end;
          ftBoolean:
          begin
          if not cdsupdate.Fields[i].IsNull then
          begin
          if cdsupdate.fields[i].value then
          sql := sql + '1' + ','
          else
          sql := sql + '0' + ',';
          end
          else
          sql := sql + 'Null' + ',';
          end;
          end;
          end;
          end;
          Delete(sql, Length(sql), 1);
          sql := sql + ');';
        end;
      usModified:
        begin
          supdate := '';
          for I := 0 to cdsupdate.FieldCount - 1 do
          begin
          if GetTableFields(aTableName).IndexOf(cdsupdate.Fields[i].FieldName) <> -1 then
          begin
          case cdsupdate.Fields[i].DataType of
          ftAutoInc, ftByte, ftShortint, ftSmallint, ftInteger, ftWord, ftLongWord:
          begin
          if cdsupdate.Fields[i].NewValue <> system.Variants.Unassigned then
          begin
          if not VarIsNull(cdsupdate.Fields[i].value) then
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + IntToStr(cdsupdate.Fields[i].value) + ','
          else
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + 'Null' + ',';
          end
          else
          begin
          if not VarIsNull(cdsupdate.Fields[i].value) then
          begin
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + 'Null' + ','
          end;
          end;
          end;
          ftFloat, ftSingle, ftCurrency, ftBCD, ftFMTBcd, ftExtended:
          begin
          if cdsupdate.Fields[i].NewValue <> system.Variants.Unassigned then
          begin
          if not VarIsNull(cdsupdate.Fields[i].value) then
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + FloatToStr(cdsupdate.Fields[i].value) + ','
          else
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + 'Null' + ',';
          end
          else
          begin
          if not VarIsNull(cdsupdate.Fields[i].value) then
          begin
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + 'Null' + ','
          end;
          end;
          end;
          ftString,ftWideString, ftFixedChar, ftFixedWideChar:
          begin
          if cdsupdate.Fields[i].NewValue <> system.Variants.Unassigned then
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + Quotedstr(VarToStr(cdsupdate.Fields[i].value)) + ','
          else
          begin
          if not VarIsNull(cdsupdate.Fields[i].value) then
          begin
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + 'Null' + ','
          end;
          end;
          end;
          ftDate, ftTime, ftDateTime, ftTimeStamp:
          begin
          if cdsupdate.Fields[i].NewValue <> system.Variants.Unassigned then
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + QuotedStr(Formatdatetime('yyyy-mm-dd hh:mm:ss', vartodatetime(cdsupdate.fields[i].value))) + ','
          else
          begin
          if not VarIsNull(cdsupdate.Fields[i].value)  then
          begin
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + 'Null' + ','
          end;
          end;
          end;
          ftBoolean:
          begin
          if cdsupdate.Fields[i].NewValue <> system.Variants.Unassigned then
          begin
          if cdsupdate.fields[i].value then
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + '1' + ','
          else
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + '0' + ',';
          end
          else
          begin
          if not VarIsNull(cdsupdate.Fields[i].value) then
          begin
          supdate := supdate + cdsupdate.Fields[i].FieldName + '=' + 'Null' + ','
          end;
          end;
          end;
          end;
          end;
          end;
          Delete(supdate, Length(supdate), 1);
          //sql := sql + ' update ' + aTableName + ' set ' + supdate + ';';
          sql := sql + ' update ' + aTableName + ' set ' + supdate ;

          scondition := ' where 1=1 ';


          for i := 0 to sl.Count - 1 do
          scondition := scondition + ' and ' + sl[i] + ' = ' + slKeyFields[sl[i]];
          sql := sql + scondition;
        end;
      usDeleted:
        begin
          sql := sql + ' delete ' + aTableName;

          scondition := ' where 1=1 ';

          for i := 0 to sl.Count - 1 do
          scondition := scondition + ' and ' + sl[i] + '=' + slKeyFields[sl[i]];

          sql := sql + scondition;
        end;
      end;
      cdsupdate.Next;
    end;
    Result := sql;
  finally
    FreeAndNil(cdsupdate);
    FreeAndNil(slkeyfields);
    FreeAndNil(sl);
  end;
----------------------------------------------
-
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 9:23:38
31楼:  feiyanm (feiyanm
你打了那么多字,何不post一段有用的大码让我学习?
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 12:24:56
32楼: 感谢楼上老铁
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 15:46:13
33楼: @sbipyps 

这个GetTableFields没有呀
----------------------------------------------
-把学习当信仰
作者:
男 grjs_2004 (grjsITname) ★☆☆☆☆ -
盒子活跃会员
2019/4/12 17:05:00
34楼: N年前,用http做数据传输,服务器端是用IIS建立服务,支持XML格式传输,只用命令Post就可以(Get其实可以不用)。

服务端建立相应的处理方案,解析XML其实都很简单。
----------------------------------------------
Everyone will to do best!
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/12 18:03:49
35楼: 一些人,得不到结果,就是活该。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/12 18:05:45
36楼: 根据 ORM,xml 的确方便。
但是 用 FireDAC DataSet Save Load bin流,更简单。
FireDAC 保存的 bin 比 xml 小。
但是 自己拼的 xml 比 bin 小。
因为 FDDataSet 保存的 xml 太多你们 ORM 不需要的内容。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/12 18:06:38
37楼: 步惊云 群里管理很多。
我不加你好友,你还可以问问别的管理。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 18:37:56
38楼: 没有使用datasnap的兄弟使用流的方式一次更新多个表吗,全是转成sql执行吗
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 18:39:49
39楼: unit clMultiStream;

interface

uses
  Classes;

type
  TMultiStream = class(TStream)
  private
    FPosition: Integer;
    FList: TList;
    function GetStream(Index: Integer): TStream;
    function GetTotalSize: Longint;
  protected
    procedure SetSize(NewSize: Longint); override;
  public
    constructor Create;
    destructor Destroy; override;
    procedure AddStream(AStream: TStream);
    function Read(var Buffer; Count: Longint): Longint; override;
    function Seek(Offset: Longint; Origin: Word): Longint; override;
    function Write(const Buffer; Count: Longint): Longint; override;
  end;


implementation

{ TMultiStream }

procedure TMultiStream.AddStream(AStream: TStream);
begin
  FList.Add(AStream);
end;

constructor TMultiStream.Create;
begin
  inherited Create();
  FList := TList.Create();
  FPosition := 0;
end;

destructor TMultiStream.Destroy;
var
  i: Integer;
begin
  for i := FList.Count - 1 downto 0 do
  begin
    GetStream(i).Free();
  end;
  FList.Free();
  inherited Destroy();
end;

function TMultiStream.GetStream(Index: Integer): TStream;
begin
  Result := TStream(FList[Index]);
end;

function TMultiStream.GetTotalSize: Longint;
var
  i: Integer;
begin
  Result := 0;
  for i := 0 to FList.Count - 1 do
  begin
    Result := Result + GetStream(i).Size;
  end;
end;

function TMultiStream.Read(var Buffer; Count: Integer): Longint;
var
  i: Integer;
  buf_pos: PChar;
  len, bytesRead: Longint;
begin
  len := 0;
  Result := 0;
  buf_pos := PChar(@Buffer);
  for i := 0 to FList.Count - 1 do
  begin
    if (FPosition < (len + GetStream(i).Size)) then
    begin
      GetStream(i).Position := FPosition - len;
      bytesRead := GetStream(i).Read(buf_pos^, Count);
      Inc(Result, bytesRead);
      buf_pos := buf_pos + bytesRead;
      Inc(FPosition, bytesRead);
      if (bytesRead < Count) then
      begin
        Dec(Count, bytesRead);
      end else
      begin
        break;
      end;
    end;
    Inc(len, GetStream(i).Size);
  end;
end;

function TMultiStream.Seek(Offset: Integer; Origin: Word): Longint;
var
  len: Integer;
begin
  len := GetTotalSize();
  case Origin of
    soFromBeginning: FPosition := Offset;
    soFromCurrent: FPosition := FPosition + Offset;
    soFromEnd: FPosition := len - Offset;
  end;
  if (FPosition > len) then
  begin
    FPosition := len;
  end else
  if (FPosition < 0) then
  begin
    FPosition := 0;
  end;
  Result := FPosition;
end;

procedure TMultiStream.SetSize(NewSize: Integer);
begin
end;

function TMultiStream.Write(const Buffer; Count: Integer): Longint;
begin
  Result := 0;
end;

end.
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 18:43:38
40楼: 网上找了个合并流的,还未试
----------------------------------------------
-把学习当信仰
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/12 18:45:08
41楼: 写一个接口 一次更新多个表
和 
写一个接口,一次更新一个表,然后,你多次调用。
有个屁的区别。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/12 18:56:54
42楼: 事务如何处理
----------------------------------------------
-把学习当信仰
作者:
男 wang_80919 (Flying Wang) ▲▲▲▲▲ -
普通会员
2019/4/12 20:12:34
43楼: 你先写出 一个接口 更新一个表的。
写不出来 第一层楼,你写什么第二层楼?
万丈高楼,更别做梦了。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/13 7:56:01
44楼: 更新一个流的函数已经写过,没有问题
----------------------------------------------
-把学习当信仰
作者:
男 sxqwhxq (步惊云) ★☆☆☆☆ -
普通会员
2019/4/13 13:54:47
45楼: wang_80919:我就开了一上午会,没答理老猫,政府工作人员开会是常事,你就踢我,请拉我回群,谢谢。
----------------------------------------------
-
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/13 17:14:21
46楼: 看来各位D友周末生活丰富,贴子不能沉。。。
----------------------------------------------
-把学习当信仰
作者:
男 iamdream (银河恒久远,梦想无止境!) ★☆☆☆☆ -
大贡献会员
2019/4/13 18:25:32
47楼: 将多个流(TStream)通过一个流传输的一个简单方法: 每次先写入流的长度,然后写入流的内容;读出时先读长度,根据长度将后面的内容读到流中。
----------------------------------------------
-广袤璀璨的银河,永无止境的梦想(梦无止境游银河) 偶的生活博客  偶的技术军事博客
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/13 19:16:52
48楼: 这个办法好!,感谢楼上
----------------------------------------------
-把学习当信仰
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/13 19:35:25
49楼: @iamdream 

如何在流留个固定长度写流内容的size,比如在流用8位表示流的内容尺寸?

ms.write(4096,sizeof(8)) 这样吗,如何把另一个memorystream流内容弄进来,用copyfrom还是write方法?
----------------------------------------------
-把学习当信仰
作者:
男 hnxxcxg (咏南中间件) ★☆☆☆☆ -
盒子活跃会员
2019/4/14 9:14:36
50楼: 分割(合并)流
https://www.cnblogs.com/hnxxcxg/p/10505843.html
----------------------------------------------
咏南中间件 QQ:254072148http://www.cnblogs.com/hnxxcxg/
作者:
男 akai1203 (w-dins) ★☆☆☆☆ -
普通会员
2019/4/14 18:48:27
51楼: 感谢咏南!
----------------------------------------------
-把学习当信仰
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v2.1 版权所有 页面执行44.92188毫秒 RSS