客户端 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;
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);
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]];
根据 ORM,xml 的确方便。 但是 用 FireDAC DataSet Save Load bin流,更简单。 FireDAC 保存的 bin 比 xml 小。 但是 自己拼的 xml 比 bin 小。 因为 FDDataSet 保存的 xml 太多你们 ORM 不需要的内容。
----------------------------------------------
(C)(P)Flying Wang
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;