Lazarus中文社区

 找回密码
 立即注册(注册审核可向QQ群索取)

QQ登录

只需一步,快速开始

Lazarus IDE and 组件 下载地址版权申明
查看: 8388|回复: 10

异构平台下多层架构思路、DataSet转换核心代码;4月18补充代码。

[复制链接]

该用户从未签到

发表于 2011-3-2 15:39:10 | 显示全部楼层 |阅读模式
背景:
1、很多情况下我们的终端与服务器是分离的,并且操作系统也可能会存在很大的不同。
2、近些年火爆的WebService技术和SaaS等概念也让我们的思想得以解放。
3、Lazarus是一款可以跨平台开发的工具,在精神上基本满足了我们Once Code愿望。
4、但Lazarus还存在很多的问题,即使原生的类、函数、过程也还会报错。
问题:
1、我需要做一个三层架构,实现WinCE(或Linux)终端进行数据采集处理。
2、涉及到跨网等情况不可能采用直连数据库的方式,而Lazarus对WebService又是一团糟。
3、我打算回到原始状态,建立三层架构(客户端、服务器、数据库)形式,客户端和服务器之间以Tcp方式进行数据交互。
4、Lazarus已经没有了TClientDataSet,经查找取而代之的是TMemDataset。
架构思路:
     1、服务器接收客户端请求,进行数据(与数据库交互)的处理,处理结果以流方式进行压缩、传输。
     2、客户端接收到流后进行解压、还原,进行本地化操作处理,将本地处理结果打包,发送至服务器。

核心技术:
1、Tcp传输,我采用lnet组件,因为它支持:Linux、Windows、Wince,参见我的另一个贴子,可以多线程处理事务。
2、DataSet网络传输,我打算做成XML再传,==吧想了很多方式但未实现,最后官网上看到了TMemDataset的介绍,用它解决了DataSet在服务器与客户端的类型化问题。
3、困扰了我两天的问题,下面是我写可行性测试代码关于DataSet处理的。

请各位笑纳:

PS:源码不太稳定,有些问题,修改后即可上传。
4月18日上传代码:
MemDataset与XML互转的代码,这里给出的已实际应用于项目,关于数据行,可以通过循环的方式来处理,
      procedure TFormMain.WriteDataSet();
var
xdoc: TXMLDocument;
noEntity,
noTable,
noColumns,
noColumn,
noPrimaryKey,
noRows,
noRow,
noField,
noValue :TDOMNode;
begin
//create a document
xdoc := TXMLDocument.create;
xdoc.Encoding := 'utf-8';
//根节点
noEntity := xdoc.CreateElement('Entity');
Xdoc.Appendchild(noEntity);
//表
noTable := xdoc.CreateElement('Table');
TDOMElement(noTable).SetAttribute('Name',UTF8Decode('TS_EMPLOYEE'));
noEntity.Appendchild(noTable);
//列集合
noColumns := xdoc.CreateElement('Columns');
noTable.Appendchild(noColumns);
//列
//第一列
noColumn:= xdoc.CreateElement('Column');
TDOMElement(noColumn).SetAttribute('Name',UTF8Decode('EMPLOYEEID'));
TDOMElement(noColumn).SetAttribute('Type',UTF8Decode('ftInteger'));
TDOMElement(noColumn).SetAttribute('Size',UTF8Decode('20'));
noColumns.Appendchild(noColumn);
//第二列
noColumn:= xdoc.CreateElement('Column');
TDOMElement(noColumn).SetAttribute('Name',UTF8Decode('EMPLOYEENAME'));
TDOMElement(noColumn).SetAttribute('Type',UTF8Decode('ftInteger'));
TDOMElement(noColumn).SetAttribute('Size',UTF8Decode('20'));
noColumns.Appendchild(noColumn);
//主键
noPrimaryKey := xdoc.CreateElement(&#39rimaryKey');
TDOMElement(noPrimaryKey).SetAttribute('Name',UTF8Decode(&#39rimaryKey'));
noTable.Appendchild(noPrimaryKey);
//主键列
noColumn:= xdoc.CreateElement('Column');
TDOMElement(noColumn).SetAttribute('Name',UTF8Decode('EMPLOYEEID'));
noPrimaryKey.Appendchild(noColumn);

//数据行
noRows := xdoc.CreateElement('Rows');
noEntity.Appendchild(noRows);
//第一行
noRow:= xdoc.CreateElement('Row');
noRows.Appendchild(noRow);
//第一列
noField:= xdoc.CreateElement('EMPLOYEEID');
noValue := xdoc.CreateTextNode(UTF8Decode('7777'));
noField.Appendchild(noValue);
noRow.Appendchild(noField);
//第二列
noField:= xdoc.CreateElement('EMPLOYEENAME');
noValue := xdoc.CreateTextNode(UTF8Decode('9999'));
noField.Appendchild(noValue);
noRow.Appendchild(noField);
writeXMLFile(xDoc,'teste.xml');
Xdoc.free;
end;

procedure TFormMain.ReadDataSet();
var
xdoc: TXMLDocument;
noEntity,
noTable,
noColumns,
noColumn,
noPrimaryKey,
noRows,
noRow,
noField,
noValue :TDOMNode;
strTable,
strColumn,
strType,
strSize,
strField,
strValue:string;
i,j:integer;
strColumns: Array of string;
mDataSet:TMemDataset;
begin
   ReadXMLFile(xdoc, 'teste.xml');
   //实体信息,可以忽略
   noEntity := xdoc.FindNode('Entity');
   Memo.Lines.Add(noEntity.NodeName);
   //表信息
   noTable :=  noEntity.FindNode('Table');
   strTable :=  noTable.Attributes.GetNamedItem('Name').NodeValue;
   Memo.Lines.Add(noTable.NodeName +' '+strTable);
   //构造实体
   mDataSet:= TMemDataset.Create(Self);
   mDataSet.Name:= strTable;
   //字段信息
   noColumns :=  noTable.FindNode('Columns');
   SetLength(strColumns,noColumns.ChildNodes.Count);
   with noColumns.ChildNodes do
   begin
        for i:=0 to (Count-1) do
        begin
          strColumn :=Item.Attributes.GetNamedItem('Name').NodeValue;
          strColumns := strColumn;
          strType   :=Item.Attributes.GetNamedItem('Type').NodeValue;
          strSize   :=Item.Attributes.GetNamedItem('Size').NodeValue;
          Memo.Lines.Add(  ' '+Item.NodeName
                         + ' '
                         + strColumn
                         + ' '
                         + strType
                         + ' '
                         + strSize
                         );
        mDataSet.FieldDefs.Add(strColumn,
                               TFieldType(GetEnumValue(TypeInfo(TFieldType), strType))//,
                               //strToInt(strSize)
                               );
        end;
   end;
   //主键信息
   noPrimaryKey :=  noTable.FindNode(&#39rimaryKey');
   Memo.Lines.Add(noPrimaryKey.NodeName +' '+noPrimaryKey.Attributes.GetNamedItem('Name').NodeValue);
   with noPrimaryKey.ChildNodes do
   begin
        for i:=0 to (Count-1) do
        begin
          Memo.Lines.Add(  ' '+Item.NodeName
                         + ' '
                         + Item.Attributes.GetNamedItem('Name').NodeValue );
        end;
   end;
   mDataSet.Open;
   //数据信息
   noRows :=  noEntity.FindNode('Rows');
   with noRows.ChildNodes do
   begin
        for i:=0 to (Count-1) do
        begin
           mDataSet.Append;
           for j:=0 to Item.ChildNodes.Count-1 do
           begin
               strValue:= UTF8Encode(Item.ChildNodes[j].FirstChild.NodeValue);
               mDataSet.FieldByName(strColumns[j]).AsString:=strValue;
               Memo.Lines.Add(strValue);
           end;
        end;
        mDataSet.AppendRecord(['15555','1111']);
   end;

   Datasource1.DataSet:= mDataSet;

   xdoc.Free;
end;        

  
   欢迎各位在群里与我交流,最个问问题的那个人就是我。

评分

参与人数 1威望 +1 收起 理由
猫工 + 1 优秀文章,支持!n神马都是浮云

查看全部评分

回复

使用道具 举报

该用户从未签到

发表于 2011-3-3 00:01:21 | 显示全部楼层
刚好正在做异构系统,打算把一个产品的服务端放在Linux系统里,也一直没找到好的解决办法呀,希望参考一下LZ的思路和源码学习一下.
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-3-3 09:39:29 | 显示全部楼层
谢谢无私分享
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-3-26 17:34:49 | 显示全部楼层
怎么修改了这么久还没有上传啊,不会太监了吧
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2011-3-28 20:20:18 | 显示全部楼层
记录锁等怎么实现呢?
没有编辑锁定的话数据的一致性和多客户端的访问就成问题了。
本人认为这个方法可以用于报表呈现,单机处理,多用户就有缺陷了,大家想想办法看,怎么在3层下解决不用复杂的程序控制记录锁(在两层时根本不用考虑记录锁的问题,数据库自己就搞定了)。
回复 支持 反对

使用道具 举报

该用户从未签到

 楼主| 发表于 2011-4-18 11:30:47 | 显示全部楼层

Re:异构平台下多层架构思路、DataSet转换核心代码

补充说明:
1、MemDataset可以与XML互相转换,解决网络下不需要直连数据库,而是以HTTP协议进行跨网、跨防火墙数据传输的问题;
2、以多线程方式,利用Tcp/IP协议以Socket方式,在终端及服务器程序间进行跨平台的数据传输;参考代码(lnet 组件 Tpc/Udp多线程数据传输示例 http://kaldemonia3_src_www.fpccn.com/read.php?tid=1098
3、终端可以使用Sqlite作为后台数据库;
4、服务器可以使用任意大型数据库直连的方式,当接收到客户端的请求命令及参数信息后,直接操作数据库,返回相应的数据集或结果信息;
   
5、当然也可以使用 CopyDataStruct 及SendMessage与.net程序之间进行消息处理,由.net程序来完成业务逻辑。

6、关于数据在网络传输过程中最好还是进行压缩的处理的。参考代码(字符串压缩、解压缩 http://kaldemonia3_src_www.fpccn.com/read.php?tid=994 )


已用上述的几个贴子的代码应用于实际项目。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2012-4-26 17:20:41 | 显示全部楼层
XML如何转为数据集 MEMDataset呢?

如果不知道 数据列是什么 有多少个的情况下,

谢谢。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2012-4-27 12:42:19 | 显示全部楼层
先收藏,谢谢LZ
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2012-5-26 13:05:24 | 显示全部楼层
楼主,思路不错,既然是使用TCP了,为什么不直接使用流来读写呢。
这样子做为中间层的转换更为方式, 取抽一个基类或者接口出来, 然后其它数据包都基于此接口操作,直接转换成流。速度更加快。
我也做过主方面的东东,多多联系交流一下。
回复 支持 反对

使用道具 举报

该用户从未签到

发表于 2012-6-5 16:39:34 | 显示全部楼层
先收藏,谢谢LZ
回复 支持 反对

使用道具 举报

*滑块验证:

本版积分规则

QQ|手机版|小黑屋|Lazarus中国|Lazarus中文社区 ( 鄂ICP备16006501号-1 )

GMT+8, 2026-7-6 20:35 , Processed in 0.054028 second(s), 10 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表