Delphi MIDAS 的重大BUG ---DelphiBBS

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情
Delphi MIDAS 的重大BUG ---DelphiBBS (2006-04-17 13:17:52)
目的:
   三层结构中客户端取数一般是采用
     TClientDataSet  =====>  TDataSetProvider + TDataSet
   有些人使用TDataSetProvider + TTable,然后在设计期间设置TTable的属性
   缺点很明显:
       1、不能使用SQL实现复杂的查询
       2、TTable的属性在设计期间完全确定了,也就只能只能打开固定的一个表,
          要使用多个表怎么办?只好在RemoteDataModule中放无数的TDataSetProvider和TTable这种做法不能满足我们的要求,我们需要的是:
     1、在Client端使用SQL语句打开数据集
     2、Provider应该能访问任意数据,
        最好做到多个ClientDataSet同时使用一个Provider访问不同的数据Delphi的帮助里没有例子,不过我们还是很容易就找到了实现方法:
     Server端:TDataSetProvider + TQuery
     Client端:TClientDataSet
     // for Delphi 5:
         TDataSetProvider.Options属性中应该包括poAllowCommandText,
         允许ClientDataSet使用SQL命令
     Client端程序:
     with ClientDataSet do
     begin
       Close;
       CommandText := 'Select xxx ......';
       Open;
     end;
     // for Delphi 4:
     手头找不到D4了,因此不知道D4是否支持TClientDataSet.CommandText,
     我们以前是这样做的:
     Client端程序:
     with ClientDataSet do
     begin
       Close;
       DataRequest('Select xxx ......');
       Open;
     end;
     Server端程序:
     TDataSetProvider.OnDataRequest(Sender: TObject; Input: OleVariant): OleVariant;
     begin
       // 这里的Input就是客户端的ClientDataSet调用DataRequest方法时传递的参数
       // 将它赋值给Query.SQL.Text就可以了
       Query.SQL.Text := Input;
     end;
     好了,用上面的方法我们在Client端使用SQL了,也使得Provider与数据集无关,
     Server端只需要公布一个Provider就可以供Client端的多个ClientDataSet使用了,看起来真不错,问题似乎得到了完美的解决  :))
---------------------------------------------------------------------
发现了BUG: :<<<
  按上面的方法,Server端使用一个DataSetProvider
  Client端使用两个TClientDataSet,都使用Server端的同一个Provider,分别打开两个表,如下:
  with ClientDataSet1 do
  begin
    Close;
    CommandText := 'Select * from Table1';
    Open;
  end;
  with ClientDataSet2 do
  begin
    Close;
    CommandText := 'Select * from Table2';
    Open;
  end;

  上面的代码中ClientDataSet与数据库表的对应关系如下:
     ClientDataSet1  =====>  "Table1"
     ClientDataSet2  =====>  "Table2"

  注意顺序为先打开表1,再打开表2
  然后我们修改ClientDataSet1中的数据,再调用
     ClientDataSet1.ApplyUpdates(-1)方法提交数据,却发现无论如何都成功不了,奇怪!
  同样的数据直接在两层C/S结构的程序中可以成功地写入表中,可以肯定数据没问题
  程序绝对正确,同样的程序早就调试通过了,现在却突然不能提交数据了,而且,奇怪的是,错误很稳定,100%提交失败,系统重起N次也没影响
---------------------------------------------------------------------
调试:
  程序和数据都没问题,实在想不出错在哪里,只好用最低级的方式了,
  打开M$ SQL Trace,睁大眼睛看提交到SQL Server上的所有SQL语句,然后,在三层结构下提交数据、在两层C/S结构下提交数据,比较SQL语句有什么不同,这下更奇怪了,程序中Insert一条记录,ApplyUpdates后看到的SQL语句是
     insert into xxxx(xx,xx,...) values(xx,xx,...)
  拿出来执行,返回的错误信息居然是'invalid column name xxxxxx',字段不存在????
  Select * from xxxx 看到字段明明在那里嘛!
  难道SQL有毛病?? 删掉表,重建,再来一遍错误一模一样,奇怪!
  重复N遍之后,终于发现,Insert语句中操作的表居然是Table2!!!
  但是程序中打开的是Table1,这么说来,MIDAS在提交数据时操作的目标表错了,跟本就不是Client端实际使用的表!
---------------------------------------------------------------------
分析:
  打开Delphi 源代码 provider.pas ,搜索ApplyUpdates之类的东西,看究竟是如何实现的,最后看到了根源,如下:
  // Delphi 源代码 provider.pas
  procedure TDataSetResolver.DoUpdate(Tree: TUpdateTree);
  begin
    with Tree do
    begin
      ...
      Source.Edit;
      ...
    end;
  end;

  procedure TDataSetResolver.DoDelete(Tree: TUpdateTree);
  begin
    with Tree do
    begin
      ...
      Source.Delete
      ...
    end;
  end;

  procedure TDataSetResolver.DoInsert(Tree: TUpdateTree);
  begin
    Tree.Source.Append;
    ...
  end;

  其中TUpdateTree.Source定义为
  TUpdateTree = class(TObject)
    ...
    property Source: TDataSet read FSourceDS;
    ...
  end;

  水平有限,具体如何没看完,不过根据前面调试的结果,和上面的源代码结合起来,
  估计这个Source: TDataSet最终就等于TDataSetProvider.DataSet
  这样一来,如果我们用同一个Provider同时打开多个表,只有最后打开的ClientDataSet可以保证Server端的TDataSetProvider.DataSet和它对应着相同的数据集二前面打开的ClientDataSet就根本不能提交了,  这样一来,我们前面提出的方案就彻底崩溃了,根本原因就在于:
  TDataSetProvider的根本就是为单个客户端设计的,完全没有考虑到同时访问多个数据集的问题,实际运行中永远只有最后打开的一个数据集能够保持存在,因而也就只有最后打开的一个ClientDatSet能提交数据成功
---------------------------------------------------------------------
结论:
  要解决应该很简单,TDataSetProvider应做以下修改:
  1、建立一个内部的DataSet队列
  2、ClientDataSet打开数据集时,创建一个新的DataSet,加入到DataSet队列中
  3、ClientDataSet关闭时,从DataSet队列中删除对应的DataSet
  4、创建新DataSet时,可以根据TDataSetProvider.DataSet属性来确定使用的实际DataSet类
     也就是说,如果DataSet指定为一个TQuery,那么就创建一个TQuery;
     如果是一个TTable,那么就创建一个TQuery
     这点很容易实现
  5、创建新DataSet后,应该将TDataSetProvider.DataSet对应的TDataSet的全部属性赋值给新DataSet
  6、定义一套规范,将ClientDataSet与DataSet队列中的TDataSet一一对应
  7、取数、传递数据包、提交数据的代码都不需要变动,只需要根据ClientDataSet
     在DataSet队列中找到对应的TDataSet,其余的工作完全一样
  说起来简单,这种事情我们做不了,恐怕应该由Borland自己来干了!
  写到最后,得出的结论基本上是悲剧性的:
  1、最初提出的方案基本可行
  2、但是绝对不能让多个ClientDataSet同时使用同一个Provider访问数据
     否则将只有最后打开的ClientDataSet能提交数据成功
  3、如果有多个ClientDataSet都需要修改数据集并提交的话,那么就不能只用一个Provider了,只好在RemoteServer中公布几个Provider
  4、注意,错误只出在"同时"访问数据时,因此轮流使用还是可以的

  唉!!真是悲哀啊!!!
Delphi代码注册Midas.DLL Delphi代码注册midas 阅读详情

相关推荐

腾讯midas支付sdk接入

简单介绍分布式服务器接入腾讯第三方支付插件后的支付流程图

书影 2872

delphi不需注册MIDAS.DLL

能不能使用TClientDataSet又不用MIDAS.DLL呢? 很简单,就是uses一下MidasLib单元! MidasLib单元在Delphi6以及DELPHI的更高版本中才有,是Lib目录下的一个dcu文件。一旦在你的源程序中引用了MidasLib单元,程序运行时就不再需要MIDAS.DLL文件。 然而,编译后程序大小一定会增加200k以上,即使使用包编译模式。

DelphiMIDAS三层完美解决方案

DelphiMIDAS三层完美解决方案,适合于三层结构的开发体系,不错的方案,非常完美,值得珍藏

Delphi 2010 V14.0.3449.21988 的Midas.dll 修正了上一版本的大BUG

上一版本的Midas.dll Delphi 2007编译的程序如果是用Delphi 2010的Midas.dll是会出错的。 这一版就不会了。 转载于:https://www.cnblogs.com/AnyDelphi/archive/2009/06/15/1503362.html...

dctc85941的博客 174

警惕!MiDaS本地部署这些坑,云端方案全避开

本文介绍了基于星图GPU平台自动化部署AI单目深度估计-MiDaS镜像的高效方案。该平台预置了CUDA、PyTorch及模型依赖环境,避免本地配置难题,支持一键启动与快速推理。用户可轻松实现图像深度图生成,适用于AR/VR、3D建模等场景的模型微调与AI应用开发,大幅提升研发效率。

YellowSun24的博客 277

DelphiMIDAS三层完美解决方案----中间层构建

思路:中间层与客户端通过三个关键的接口过程进行交互操作(GetData,SetData,GetspData) GetData:获取数据集。客户端传递数据集名称给中间层,中间层根据请求的数据集名称从数据库的配置文件中获取相关信息,与客户的的条件集合一起给合成SQL语句 SetData:提交数据集。客户端传递修改后的数据集Delta与名称给中间层,中间层根据请求的数据集名称从数据库的配置文件中获取相关...

编程资料收集与共享交流 2359

DelphiMIDAS的全面学习

(一)MIDAS是什么?   DelphiMIDAS到底是什么呢?和他相关组件是什么呢? MIDAS(Multitiered Distributed Application Services)多层分布式应用服务。   Delphi所提出的Multi-Tier结构是把原来的Two-Tier前台应用程序内的dbExpress,ADO,BDE,SQL Link,DataMoule,拿到另外

Tercel99的专栏 3716

判断数据集 是否修改(DataSet)

DataGridView 绑定 的时候记得添加    dataGridView1.DataSource = ds;             dataGridView1.DataMember = ds.Tables[0].TableName;             //已方便后期判断ds是否修改了             ds.AcceptChanges(); 保存时:  private void

xushichang的专栏 4388

Connection Timeout和Command Timeout

每次对数据库连接时,我们有时候会碰到连接超时或者命令超时,这两个超时是不一样的。以ADO.NET为例,当客户端和服务器端连接时,碰到的超时情况主要有下面几种: 当从连接池获取一个连接时,碰到超时。 当建立一个全新连接(而不是从连接池获取)时,碰到超时。 当发送一个命令(command)到SQL Server时,超时。 当发送命令(连接字符串带有“context connection=tru

菜鸟学编程 2万+

Delphi分布式系统(MIDAS)中动态调用存储过程

From: www.ccw.com.cn 一、前言     现在,多层应用程序已经和其他计算机技术一样越来越多地被谈论。多层应用程序和传统的客户/服务器应用程序相比,前者有更多的优点。而B o r l a n d的Multitier Distr

turbocc 因程序而激情 1642

Delphi中创建MIDAS服务器并注册(MIDAS之二)

Delphi中如何创建并注册MIDAS应用程序服务器COM程序   Delphi提供一些向导(如:RemoteDataModule,Automation Object,TypeLibrary)来自动产生COM程序的结构.   (法1)创建一个普通应用程序服务器        新建一个普通工程,然后通过New->Other->Multitier->Remote DataModule,来自动新建一个C

敦格 2835

delphi_MIDAS服务端自定义函数

delphi_MIDAS服务端自定义函数 包括DCOM接口调用 SocketConnection DCOMConnection 运用

delphi midas 修改scktsrvr端口

delphi midas 修改scktsrvr端口

DELPHI midas应用问题集锦

多层结构程序设计中应用DELPHI midas 应用问题集锦

delphi midas配置

======1、在服务器上运行dcomcnfg程序,一,在默认属性中 1,把在该机上启动分布式com与在此计算机上启用com internet services 打勾.2,默认验证身份级别设为无。默认模婗级别设为标识。二,在默认安全机制中的默认访问权限和默认启动权限中编辑默认值中必须加入可能是分机上登录用的客户名称(users),否则会提示“拒绝访问”三,选择应用程序(先把服务器程序在服务器上运行

devil_angel的专栏 1450

delphi2007的midas.dll有问题

如果表里有流字段,savetofile再loadfromfile后会丢掉一部分数据。delphi7的midas.dll就没有这个问题。

JUST DO IT. 872
上一篇: 史上最全版本自动更新程序及3种实现策略-分析文档(UML图)
下一篇: DataSnap 新特色
tomliks
博客等级 码龄19年 10粉丝 1原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值