大家讨论讨论如何设计一些通用性的东西,不要把客户端写死
比如通用的查询,通用的报表系统,通用的窗体调用方式,通用的录入界面设计

解决方案 »

  1.   

    通用的查询很简单,在应用服务器上挂一套Query、DataSetProvider,设置DataSetProvider.Options的poAllowCommandText=True,随时设置客户端ClientDataSet.CommandText,调用Open或者Execute向应用服务器发送SQL语句,可完成你对数据库的任意操作。
      

  2.   

    你的查询一点也不具体,
    查询的界面是统一的呢,还是每个功能模块都要重做
    查询的sql串是保存在数据库的呢,还是直接写在客户端的
      

  3.   


    我的几个关键类的结构如下:
    (数据库的表结构和字段定义我都用存储过程自动产生到我定义的几个Access表中,放在客户端)//字段定义类
    TFieldDef=class(TObject)
    public
         //字段所属表名称
         TableName: String;
         //字段名称
         FieldName: String;
         //字段在表中的顺序
         FieldIndex:integer;
         //当前值
         Value:Variant;
         //旧值
         OldValue:Variant;
         //字段显示名称
         DisplayName: String;
         //字段显示类型
         DataType:String;
         //字段类型
         FieldType:String;
         //字段长度
         FieldLength:integer;
         //是否允许为空
         AllowNull:boolean;
         //精度
         Precision:integer;
         //小数位数
         Scale:integer;
         //缺省值
         DefaultValue:String;
         //是否为关键字段
         IsKeyField:boolean;
         //相关查询名称
         QueryName:String;
         class function  ToControlName(Str:String):String;
         class function  ToFieldName(Str:String):String;
    end;
    TFieldDefs=class(TObject)
    字段定义集
    private
         //字段定义列表
         FieldList:TList;
    protected
         //按名称访问一个TFieldDef
         function GetFieldDef(const FieldName:String):TFieldDef;
         //按索引访问一个TFieldDef
         function GetItems(const i:integer):TFieldDef;
         //按名称查找到一个TFieldDef
         function FindField(FieldName:String):TFieldDef;public     constructor Create;
         destructor  Destroy;
         function   GetFieldCount:integer;
         //将所有的字段定义都删除掉
         procedure Clear;
         //清空所有值
         procedure ClearAllValues;
         //加入一个TFieldDef到FiledList
         procedure   AddField(Field:TFieldDef);
         //按字段名称删除一个FieldName
         procedure   DeleteField(FieldName:String);
         //按名称访问一个字段
         property FieldDefs[const FieldName: String]: TFieldDef read GetFieldDef ; default;
         //按索引访问一个字段
         property Items[const i:integer]:TFieldDef read GetItems;end;业务定义类
    TBussinessDef=class(TObject)
    private
         //待操作的主表
         MainTableName:String;
         //表单名称;
         //所有与该业务类相关的字段
         BaseFields:    TStringList;
         //待选择字段
         SelectFields:  TStringList;
         //待更新字段
         UpdateFields:  TStringList;
         //待插入字段
         InsertFields:  TStringList;
         //关键字段
         KeyFields:     TStringList;
         //所有与该业务类相关的表
         AllTables:     TStringList;
         //填写缺省值的动作
         SelectWhere:   String;
         //缺省值定义条件
         DefaultValues:TstringList;
         constructor Create;
         destructor  Destroy;
    public
         IniActions:    TStringList;
         //缺省的Where语句部分的值
         Caption_:string;     
    end;所有窗体的相关定义
    TFormDef=class(TObject)
    public
       Name:String;
       DisplayName:String;
       QueryDefName:String;
       TreeDefName:String;
       FormType:String;
    end;
      

  4.   


    所有窗体的相关定义集
    TFormDefs=class(TObject)
    private
         //Form定义列表
         FormDefList:TList;
    protected
         //按名称访问一个TFormDef
         function GetFormDef(const FormDefName:String):TFormDef;
         //按索引访问一个TFormDef
         function GetItems(const i:integer):TFormDef;
         //按名称查找到一个TFormDef
         function FindFormDef(FormDefName:String):TFormDef;
    public
         constructor Create;
         destructor  Destroy;
         function    GetFormDefCount:integer;
         //加入一个TFormDef到FiledList
         procedure   AddFormDef(FormDef:TFormDef);
         //按Form名称删除一个FormName
         procedure   DeleteFormDef(FormDefName:String);
         //按名称访问一个Form
         property    FormDefs[const FormDefName: String]: TFormDef read GetFormDef ; default;
         //按索引访问一个Form
         property    Items[const i:integer]:TFormDef read GetItems;
    end;查询定义
    TQueryDef=class(Tobject)
    private
    public
         //查询名称
         QueryName:String;
         //查询方案名称
         QuerySchemaNames:TStringList;
         //所有字段              -
         AllFields:TStringList;
         //缺省定义条件
         DefaultCondition:String;     constructor Create;
         destructor  Destroy;
         procedure   Clear;
    end;
    TEasyConditions= array [0..2] of TStringList;TComplexConditions=array [0..7] of TStringList;查询方案类(一个查询对应多个方案)
    TQuerySchemaDef=class(TObject)
    privatepublic
         //查询名称
         QueryName:         String;
         // 查询方案名称
         QuerySchemaName:   String;
         //简单查询条件
         EasyConditions:TEasyConditions;
         //复杂查询条件
         ComplexConditions: TComplexConditions;
         //显示字段
         ShowFields:        TStringList;
         //排序字段
         SortFields:        TStringList;
         constructor Create;
         destructor  Destroy;
         procedure   Clear;
         function    GetAllContents:String;end;
      

  5.   

    这个业务类是将界面上的Edit控件值取出来后,自动生成SQL语句(update,insert,delete,select)我去控件值的设计思想是,将Edit控件名称起为表名称_子段名称的形式,比如
    Personel_Name,然后根据子段定义列表中的字段名称(比如Personel.Name),在界面上用TForm.FindComponent找到该字段对应的控件并将其
    值取出,送入TFieldDefs数组,自后TBaseClass根据TFieldDefs数组中的值产生
    SQL语句,(产生规则在TBussinessDef重定义,这个类的值是从本地Access表取出的)。
    我用明文传送的SQL,当然也可以加密,但我懒得考虑得太复杂了。TBaseClass=class(TObject)
    private     DefLoader:TDefLoader;
         Locator:TStringList;
         //产生选择一条纪录的SQL语句
         function    CreateSelectSQL:String;
         //产生插入一条纪录的SQL语句
         function    CreateInsertSQL:String;
         //产生更新一条纪录的SQL语句
         function    CreateUpdateSQL:String;
         //产生删除一条纪录的SQL语句
         function    CreateDeleteSQL:String;
         //产生一个定位条件
         function    CreateLoactionString:String;
         //执行产生的SQL语句
         function    ExecuteSQL(SQLString:String):boolean;
         //将当前值存入旧值
         procedure   SaveToOldValues;
         //将当前值还原为旧值
         procedure   GetFromOldValues;
         procedure SetDataInClient(const Value: boolean);protectedpublic
         FDataInClient:boolean;
         //是否允许选择一条纪录
         SelectEnabled:boolean;
         //是否允许删除一条纪录
         DeleteEnabled:boolean;
         //是否允许更新一条纪录
         UpdateEnabled:boolean;
         //是否允许插入一条纪录
         InsertEnabled:boolean;
         //业务名称
         BussinessName:String;
         //字段定义
         FieldDefs: TFieldDefs;
         //控制各界面是显示为立体的还是平面的
         Ctl3D:boolean;
         BussinessDef:TBussinessDef;
         constructor Create(BussinessName:String;DefLoader:TDefLoader);
         destructor  Destroy;
         procedure   Initialize;
         //清空字段列表中的值
         procedure Clear;
         //设置每次插入一条纪录需要设置的初始值
         procedure   SetIniValues;
         // 选择一条纪录
         function    SelectRecord(LocationList:TStringList):Boolean;
         // 插入一条纪录
         function    InsertRecord:Boolean;
         // 更新一条纪录
         function    UpdateRecord:Boolean;
         // 删除一条纪录
         function    DeleteRecord(LocatorList:TStringList):Boolean;
         //选择多条纪录
         //设置业务类中一个字段的值
         procedure   SetFieldValue( FieldName:String; Value:Variant );
         //取得业务类中一个字段的值
         function    GetFieldValue( FieldName:String ) :Variant;
         procedure   CancelEdit;
         //设定定位条件
         procedure   SetLocator(LocatorList:TStringList);
         //取得Fields列表中所有字段所对应的中文名称
         procedure GetFieldNames(Fields:TStringList;var Names:TStringList);end;
      

  6.   

    在三层结构中,SQL语句是放在客户端好还是放在中间层上好?
      

  7.   

    问题:
    如何设计一些通用性的东西,不要把客户端写死我的看法:
    一、要有一个解释器(或者是生成器)。
    二、界面的描述:把Delphi的.dfm文件用数据库table表达出来。界面动态生成。
    三、模仿Delphi的Open Tools API的方式,实现功能的扩展。
    四、带有玩笑性质的话:当所有的都是用代码“写”出来的,而不是用鼠标拖拉的时候,你的目标就很近了。(这里的“写”:很大程度是解释器帮忙)
      

  8.   

    SQL语句放在客户端还是三层吗?
      

  9.   

    http://www.csdn.net/cnshare/soft/13/13647.shtm
    表面上似乎不怎么样,但我这个软件便已有采用通用的形式接管输入输出之意,同时能够完成一部分简单计算功能,以便于不同平台的移植,大家不妨免费试用一番。
    感谢CSDN。
      

  10.   

    广告时间http://expert.csdn.net/Expert/topic/1274/1274239.xml?temp=.1771356请多关注,多谢
      

  11.   


    对于通用型的软件建议:最好的做法,放弃原始的关系数据库的观念,完全用面向对象的方式思考。你可以把对象直接存放在数据库中,数据库的一个表对应一个类,其中具体的行,表示一个对象。这样,客户端程序在启动的时候实际上是从数据库中重建对象,而不是根据表格的数据,以及相互关系来动态的生成对象,这样的工作要轻松很多。中间层主要职责就改变了,他决定根据不同的客户给他们不同的对象,比如,如果是一个浏览器客户,他就把对象封装成HTML对象。并且根据用户的权利,决定给予的对象,和可用的对象。所谓的业务逻辑完全封装到了对象当中,网络传输问题,很容易解决。在整个数据库当中,数据都成为了对象的私有数据,对象间的关系构成了全部的业务逻辑。要变更这些关系是相当容易的!拥有强大的可扩充性。界面的改变也是很容易的,你只需要替换掉对象,或者扩展类,客户端的界面就会改变。对象存放在数据库中是一个绝对的选择,你可以把一个表看成一个类,其中的一行看成一个具体的对象,字段看成这个对象的属性和方法。当然你可以有另外的看法,把一个字段看成一个对象,把对象间的关系用表之间的关系表达。我的想法不成熟,有空的时候,准备做一个这样的框架。把对象的生成、传输、存储的框架做出来。我不喜欢所谓的没有状态的对象,对象本来就应该是有状态的!这样才符合常规的思路。
      

  12.   

    to BlueTrees(蜗牛)您的想法已经有三方公司实现了请参考
    1.Delphi 7的Bold
    2.Instant Object http://www.seleqt.com
      

  13.   

    to BlueTrees(蜗牛) 
    一个表对应一个类 太细
    我觉得应 一个简单业务(可能包含几张表)对应一个类 当成一个值对象 (J2EE)
      

  14.   

    可能这样做好一些,把类的类型信息存放到一组公开的系统表格中,这组表格当然还要表达类之间的继承关系,这很容易做到,只要增加一个指向父类的字段就可以了,还要增加一个字段指出它的实例化表。一张表对应一个类,这是没有办法的,按照我上面的设想只能这样做。一个对象还需要有保存和公共的属性,这样就增加这个实例表的字段,需要保存的属性作为一个字段,在程序中对象之间包含是通过指针,在这里只能通过唯一的一个识别号来区分。这样就还需要增加对应类表一个字段,这个字段存放所有需要公开和保存的属性的名称和类型。可以根据类表来生成实例表。客户端根据类表的类型信息生成对象,并加载指定的数据库中的实例的公开和保存的属性。我把这些数据库中的实例,称为对象影子,就是加载对象影子。客户端程序修改了对象属性,如果影响到了对象影子的值,那么就自动的向服务器端提交修改后的影子,服务器端的程序负责向所有引用这些影子的客户端通报影子修正的情况。阅读和修改影子需要权限,也就是说某些对象在客户端是禁止生成的。修改影子,在服务器端串列化,保证数据一致。这些需要一个框架,需要做出具有这些能力的基础类,然后自己的程序才有可能在这些类的基础上开发,服务器端,不需要一个应用程序,也可以做成基础类,交给开发者去开发。以上的这些,我觉得在Delphi中已经有可能实现,但是没有时间来做。可以作出一整套的元件,帮助开发者容易的实现这些面向对象的数据库应用。谁来开发呀?一起做啊!
      

  15.   

    在做三层结构时,应该把SQL语句或者说是凡是直接与数据库打交道的操作放在数据服务层(中间层),中间层可以函数的形式公布接口让客户端调用,比如PerforSQL(),这些函数可以使用SQL语句或其它的逻辑代码对数据库进行操作,客户端以静态绑定或动态绑定的方式来调用中间层的函数接口。
    窗体太多了,用DLL嘛,那又什么关系,WINDOWS系统本身不是DLL组成的吗?
    建它几十个DLL也没什么大问题
      

  16.   

    to xwyaxp(阿雨):困难在于,我们最终发现数据结构和面向用户的界面不是完全分开的,用户界面往往和数据结构有密切的关系,所以才有了这样的讨论。两种解决的办法:
    1、根据数据结构生成界面,但是需要生成界面的指导信息,这些信息也要存放在数据中,这就是上文,宋的解决方案。2、把界面和数据结构捆绑在一起,构成对象,这就是我提出的方案的实质。
      

  17.   

    BlueTrees(蜗牛) :
    提出的两种解决办法,我认为应该结合使用。
    办法1是元数据。
    办法2是对象组合(类似J2EE的复合视图)。
    没有1,则对象组合的最小粒度不好把握。所以1要尽可能的“细”。
    没有2,则太细的粒度,使用不方便,所以需要“组合”。“细”到什么程度,很难把握,可能重构是较好的解决办法。
      

  18.   

    Dephi就是一个通用的录入、查询、报表系统,你们想干吗,不如洗洗睡了
      

  19.   

    to wangyi03(梅雅,你在哪里):
    我的Email : [email protected] 
    没有QQ和MSN(我连用都不会用)关于填写代码显示中文的问题并不会影响通用性的问题,这个好解决。
    我的TFieldDef对象存放了与该字段相关联的外建信息,
    比如SystemUser.Domain 与Domain.Code 有外建关联,
    Domain.Code是区域编号  Domain.Name是区域名称
    那么SystemUser.Domain对象对应的TFieldDef.QueryName中就存放了类是
    Domain(Code;Name)的信息,当在用户所属区域下拉匡点是,产生Select Domain.code ,Domain.Name From Domain,探出的是一个表格窗体,让用户选择,我会同时保存代码和名称
    但产生SQL时,我只用到了代码。
      

  20.   

    BlueTrees(蜗牛) 的想法太超前了,事实上将对象存入数据库,就是目前
    SQL Server,Oracle正在解决的,不过完全面对对象的数据库要到几年后才可以实现,现在Oracle只实现了一部分:存对象。完全面对对象的数据库实现后,我们面对的就不是 Insert ,delete,update,
    而是Object.add,object.delete,object.update,
    表之间的关联要被 Object.RelateObject取代。
    我准备春节总结,估计春节后会总结出一套方案的,敬请期待!!!!!!!!
      

  21.   

    事实上,我觉得BlueTrees(蜗牛) 的想法并不太超前,已经有很多人在研究这类问题了,这就是解决Class 和 RDBMS 之间的关系。 在Java和C++中有所谓的O/R Mapping( Object-Relational Mapping) 技术,就是解决此类问题的。
        上次,李维到上海来看技术沙龙的时候讲 DataComponents 将是下一个OO的技术热点,而O/R Mapping 是DataComponents的雏形。
        要了解更多可以到 www.object-relational.com看相关的文章,或在google中用 object relational Mapping 进行Search
      

  22.   

    BlueTrees(蜗牛) 
    你的想法很有趣,我只问你一个问题,统计如何实现?
      

  23.   

    楼上大家所讨论的所有功能我基本上都实现了,也用到了你们所讲的绝大部分方法!可以是单机,可以是C/S,只是现在我采用的是传统的方法!效率上觉得还有不少问题,以后我估计会采用完全面向对象和组件设计的思想来代替吧!已完全升级到多层!大家可以提提意见,多多讨论,多多益善!现在的具体功能:
    1 完善的数据管理:增加,删除,修改,查看
    2 操作简易的数据查询
    3 完善的统计功能:总和,最大,最小,平均
    4 灵活的打印:输出到MS WORD后再打印
    5 独特的回收站功能:有效防止误删除
    6 精美的操作界面:让你在享受中完成你的任务
    7 大量的扩展支持:QQ,ENAIL,上网。IP检测,ICQ,短信等
    8 强大的自定义功能:
    1) 可以任意新建一个树结构的表的系统
    2) 可以对已经建立好的系统进行任意修改
    3) 支持众多的数据库类型(由于采用了ADO体系,所以不但支持ACCESS,SQL SERVER,ORACLE等,也支持EXECL等!)
    更多
    http://systemer.51.net/
      

  24.   

    好的OOP+数据字典!!!
    尽量减小DFM,不要用不必要的图片!
      

  25.   

    哦,关于这个,你得看看erp的书,上面讲的有很多种企业的业务流程,要不你到一些厂里去调研
      

  26.   

    大家能说一下在三层中
    你们的clientdataset的fields的label是怎样产生的吗?
    相信如果要通用我们便不能够将fields写死在客户端的clientdataset中。
      

  27.   

    大家能说一下在三层中
    你们的clientdataset的fields的label是怎样产生的吗?
    相信如果要通用我们便不能够将fields写死在客户端的clientdataset中。
    这是一大难点!!!!!
      

  28.   

    面向对象的数据库不但有,而且已经死掉了,是Informix做的。
    原因是没人用,市场不好,害得自己被IBM收购了。
    目前的都是过渡产品,需要N年。