项目需要,做http+rest服务以及三层数据库程序。 使用了DataSnap+FireDAC.
主要问题集中在主明细多表联动更新上。
两种实现方式,一种是单表方式。主表明细表都单独更新,可以将主明细表一个函数都发服务端。
服务端创建事务,先更新主表,再更新子表。 同时查找自更新字段,及子表的外键,在提交前记录,提交后记录,并返回客户端相应新值。这种方式简单可靠。就是代码多些。但稳定。
另一种方式是采用FDSchemaAdapter关联FDMemTable + FDTableAdapter + FDCommand, 或者关联FDQuery. 该方式代码少,但设置复杂,坑主要在这里。
1. 提交Detail或下发DataSets可以用TStteam, string, 或者TFDJSONDataSets,TFDJSONDeltas.
可以借助TFDJSONInterceptor 对其进行TJSONObject-String的互转。推荐TFDJSONDeltas.方式。省得手动设置StoreItem.
var
bak:TFDStoreItems;
begin
bak := tb.ResourceOptions.StoreItems;
tb.ResourceOptions.StoreItems := [siDelta,siMeta];
try
tb.SaveToFile('detailsa.txt', sfJSON);
finally
tb.ResourceOptions.StoreItems := bak;
end;
2. 服务器子表必须设置
DtailCascade=rue. 主表键更新,子表外键自动更新。
DetailServerCascade=true Deltas只有子表无主表时,设置这里可以防止报错。重要!!!!重要!!!!重要!!!!
3. 客户端发送来的Delta信息要解析到服务器的主明细表上,然后才能用FDSchemaAdapter读入。否则可能会报错。
-----------查询------------
try
qm.open( TEncrypt.DecryptString(msql));
qd.open( TEncrypt.DecryptString(dsql));
Result := TFDJSONDataSets.Create;
TFDJSONDataSetsWriter.ListAdd(Result, qm);
except
on e: Exception do
begin
GLog.Error('TDMDB.qrymd:' + e.Message);
raise;
end;
end;
--------提交----------------
mt := TFDJSONDeltasReader.GetListValue(value, 0);
qm.SQL.Text := 'select * from ' + mt.Table.TableList.ItemsI[0].SourceName;
qd.SQL.Text := 'select * from ' + mt.Table.TableList.ItemsI[1].SourceName;
qd.MasterFields := mt.Table.ChildRelations[0].ParentColumnNames;
qd.IndexFieldNames := mt.Table.ChildRelations[0].ChildColumnNames;
mt.Table.TableList[0].Name := 'qm';
mt.Table.TableList[1].Name := 'qd';
CopyDataSet(mt,FSA);
4. 测试发现运行过程中修改FDAdapterTable的SchemaAdapter, Adapter等属性会报异常。 所以设置好这一堆组件的关联后运行时尽量就不要动了。 尤其是组件间的引用。
5. That's OK!!!.