拿来主义的确实用,但自己思考些东西更有乐趣.讨论的主题不算什么新东西,这个标题是仅希望更多喜欢DELPHI的人加进来关注和讨论.

解决方案 »

  1.   

    我试着写过这样的下面的几种代码:
      TPerson = class
      private
        ...
      public
        property 姓名: TField;
        property 性别: TField;
        property 出生日期: TField;
      end;
    可是 TField 可以有 AsString, AsInteger, AsFloat...多种写法.数据类型不严谨.
      TPerson = class
      private
        ...
      public
        property 姓名: string;
        property 性别: Boolean;
        property 出生日期: TDateTime;
      end;
    后来感觉仅仅样还不够, 如果数据库里的值是NULL就有麻烦了.曾经也试着传TDataSet,感觉也不方便.
      

  2.   

    hibernate一张表对应一个配置文件和对象文件一个dao文件,如果delphi也写类似的东西就是一个pas文件一个类,一旦多了,这些是要被编译到exe或dll里面的,启不是很大....
    我觉得还是用delphi的三层架构吧
      

  3.   


    type 
       TData = reacord ???
      

  4.   


    感觉照搬HB的方式是不行,借鉴一此东西还是可以的.Delphi的三层又能怎么样?
      

  5.   

    delphi支持泛型后,曾经想这样.但GetValue里不知道怎么写好了.type
      TXValue<T> = class
      private
        FIsNull: Boolean;
        FValue: T;
        function GetValue: T;
        procedure SetValue(const Value: T);
        function GetIsNull: Boolean;
      public
        constructor Create;
        procedure SetNull;
      public
        property XValue: T read GetValue write SetValue;
        property IsNull: Boolean read GetIsNull;
      end;...function TXValue<T>.GetValue: T;
    begin
      if FIsNull then
        ????  raise Exception.Create('The Value is: Null');
      else
        Result := FValue;
    end;
      

  6.   

    http://download.csdn.net/source/795600
      

  7.   

    就一个asString就行了
    其它类型,使用者自己去转换
      

  8.   

    妖哥这么说真我感觉无地自容中啊.
    //------------------------------------
    kwer
    (逐水)
    http://download.csdn.net/source/795600回头下载学习一下.
    //------------------------------------
    sz_haitao
    (解释型delphi?notes)
    就一个asString就行了
    其它类型,使用者自己去转换
    考虑过这样,后来觉得这样不能编译时检查类型了.
    //-------------------------------------abclm
    (♬挥霍的青春♬)
    多多指教.
    //---------------------------------------XD19861130
    (门前一棵草)
    哎,别拿我开涮了, 我这点水....
    //--------------------------------------
      

  9.   

    这回简章点来了,请多拍砖指教.TXValue = class
    private
      FFieldName: string;
      FData: TClientDataSet;
    public
      constructor create(AValueObj: TValueObject);
      procedure SetNull;  //设置NULL值
      property IsNull;
    end;TIntValue = class(TXValue);
    TDateTimeValue = class(TXValue);
    ...
    基本上和TField的子类对应.TValueObject = class
    priate
      FData: TClientDataSet;
    public
       procedure MergeChangeLog;
       procedure CancelUpdates;  
       ...将CDS有用的方法/属性"暴露"出来.
      property Modified: Boolean;
    end;//由工具生成
    TPerson = class(TValueObject)
    public
      姓名: TStringValue;
      生日: TDateTimeValue;
      ...
    end;TDBXXX = class
    public
      //根据CDS.Delta生成insert.update, delete语句.
      procedure SaveToDB(AValueObj: TValueObject); 
      ...
    end;
      

  10.   

    看到//根据CDS.Delta生成insert.update, delete语句.
    想起我的MIS框架:上方的browser(每记录占1行),下面是edit(半屏都是1条记录的各个字段)
    load(把上方的当前记录的各个字段显示到下面的各个Tedit)和save()也都是提供按钮由用户按
    具体的行为则是自动进行的,无须为每个table写对应的加载和保存代码
    这样,根本没感觉有使用hibernate的需要。。
      

  11.   

    CSDN不能连续回复三次... 继续.
    大体的思路是TXValue保存对应的数据库表的 列名. TXValue的子类的直接取TVolueObject内部CDS对应 字段 的值.TIntValue = class(TXValue)
    public
      property Value: Integer read GetIntValue;
    end;function TIntValue.GetIntValue: Integer;
    begin
      FData.FieldByName(FFieldName).AsInteger;  //如果是TDateTimeValue则AsDateTime;
    end;TValueObject的内部用TClientDataSet,方便数据的"克隆",并且可以执行"撤消".保存"结点"等功能.TValueObject的子类对应数据表, 代码可以写个工具来生成.比如上面的TPerson;
      

  12.   

    我觉得直接用TDataSet有几个问题.
    1. 写FieldByName('XXX').Value时可能会拼错字段名. 另外偶尔字段名变的时候还要检查代码,一处一处改. (或用工具).所以大多时候要双击数据集加入字段.
    2. TField的 AsXXXX有时候方便,有时候也会带出问题.
    3. 查询返回TDataSet时意义不明确. TDataSet应该是算是"记录"的集合. 用主键查的时候至多返回一条记录.另外. DELPHI的DBX中有了TDBXRow.
    //------------------
    sz_haitao
    (解释型delphi?notes)
    "这样,根本没感觉有使用hibernate的需要。。"想在DELPHI中全照搬过来可能行不通. 但我觉得HB里的不少东西还是值得借鉴的, 想办法在DELPHI中实现/模仿也是挺有乐趣的.
      

  13.   

    感谢 kwer 提供的代码.我觉得下面几个问题是不是值得推敲一下.(说的不周之处请见谅).
      TDataField = class(TPersistent)
      private
        FCaption: string;
        FName   : string;
        FIsNull : boolean;
        procedure SetCaption( const Value: string );
        procedure SetName( const Value: string );
      public
        constructor Create( Name : string ='' ); virtual;
      published
        property IsNull   : Boolean read FIsNull;
        property FieldName: string read FName write SetName;
        property Caption: string read FCaption write SetCaption;
      end;  TFInteger = class( TDataField )
      private
        FValue: Integer;
        function  GetValue(): Variant;
        procedure SetValue( const Value: Variant );
        procedure SetIntVal( const Value: Integer );
        function  GetStrValue: string;
      published
        property FieldName;
        property Caption;
        property Value: variant read GetValue write SetValue;
        property AsInteger: Integer read FValue write SetIntVal;
        property ToString: string read GetStrValue;
      end;
    ...
      TFDateTime = class(TDataField)
    ...
    1. TDataField的FieldName是不是可以隐藏掉.
    TDataSetProxy 的 constructor Create( aDataSet: TDataSet; KeyIndex: Integer =0 ); virtual;在创建时已经执行"绑定"了.2.     property Value: variant read GetValue write SetValue;
    是不是可以不要这个属性.既然已经细分了TDataField类型,(如Fint, Fnumber, Fdatetime.)
    用这个属性在赋值的时候不能进进编译时值的检查.是不是可以去掉.3. 设置NULL值如何处理.虽然可以使用上面的property Value: variant, 不如直接有个SetNULL的方法.
      

  14.   


      TDataSetProxy = class( TPersistent )
      private
        FDataSet  : TDataSet;   // 数据成员
        KeyIndex  : Integer;
        FKeyFieldName: string;
        FFieldList: TObjectList;// 保存字段类型实体
        FCount    : Integer;
        FRTTI     : TClassRTTI;
        FDataSetConnected: Boolean;
      private
        procedure Initialize; virtual;
      public
        constructor Create( aDataSet: TDataSet; KeyIndex: Integer =0 ); virtual;
        destructor Destroy; override;
      protected
        function  fnValidProperty(): Boolean;
        function  GetDataField(Index: Integer): TObject;
        function  GetDataEntity(FieldName: string): TObject;    function  GetIntegerField( Index: Integer ): TFInteger; virtual;
        function  GetNumberField( Index: Integer ) : TFNumber; virtual;
        function  GetStringField( Index: Integer ) : TFString; virtual;
        function  GetVariantField( Index: Integer ): TFVariant; virtual;
        function  GetBooleanField( Index: Integer ): TFBoolean; virtual;
        function  GetDateTimeField( Index: Integer ): TFDateTime; virtual;
        function  GetBlobField( Index: Integer ): TFBlob; virtual;
      public
        function  GeTDataFieldValue( DataEntity: TDataField ): Variant;
        procedure BeginEdit();
        procedure EndEdit();
        //*********数据集操作*********************
        procedure First();
        function  Next() : Boolean;
        function  Prior(): Boolean;
        procedure Last();
        function  Locate( Value: Variant ): Boolean; overload; // 定位
        function  Locate( EntityField: TDataField ): Boolean; overload;    function  Delete( KeyValue: Variant ): Boolean; overload;
        function  Delete( KeyField: TDataField ): Boolean;overload; //删除实体
        procedure Insert(); overload;                        // 实体的全部成员插入数据库
        procedure Insert( DataFields: array of TDataField ); overload;
        procedure Update( KeyField: TDataField ); overload;   // 修改全部实体内容
        procedure Update( KeyField: TDataField; DataFields: array of TDataField ); overload;  public
        property DataSet  : TDataSet read FDataSet;
        property KeyField : string read FKeyFieldName;      //关键字段
        property Connected : Boolean read FDataSetConnected write FDataSetConnected;
        property Count    : Integer  read FCount;
        property FieldList[Index: Integer]: TObject read GetDataField; default;//index是可信任的
        property FieldByName[FieldName: string]: TObject read GetDataEntity;
      end;在程序代码中定义了  THR_Employee = class(TDataSetProxy)
      published
        property Emp_id : TFString index 0 read GetStringField;
        property Emp_name : TFString index 1 read GetStringField;
        property Birthday : TFDateTime index 2 read GetDateTimeField;
        property Photo : TFBlob index 3 read GetBlobField;
        property Memo : TFString index 4 read GetStringField;
      end;1. THR_Employee表示一个员工还是一组员工?
    2. THR_Employee是个(ValueObject)值对象还是什么?
    3. THR_Employee继承自TDataSetProxy是不是知道的太多了?
    4. 如果再有TOrder, TOrderItem都承继自TDataSetProxy, 提交时事务如何处理?
    5. procedure Update( KeyField: TDataField; DataFields: array of TDataField ); overload;
       更新前"键"应该是已知的,而不应该让"使用者"去指定.先说这么多,不周之处请见谅.
      

  15.   

    个人偏爱用record形式
    用工具根据Table结构生成对应的record定义以及针对这些record的读取、增加、删除、更新函数,
    如:
    Function InsertGuest(var G : TGuestRecord; var NewID : integer ) : Boolean;
    使用起来方便,用户层只需要整理好这个record的数据,就可以调用相应的函数来增加删除修改读取了,完全不理会到底是怎么增加的,查询也提供一个Record,附带一个各值的计算规格,以及min ,max值得注意的是以下情况:1.多表查询,2.单表查询部分字段的值(以及多表查询时,某些表只查询部分字段的情况,
    再生产一个RecordToStr的过程,就方便作Socket的三层了
      

  16.   


    如果表结构因为其它应用(如asp/jsp)需要而变化了,delphi程序也需要重新生成pas文件、重新编译吗?
      

  17.   


    这种情况几乎是不可能的,除非业务永远不会有变化或者变化的非常非常小.界面和业务逻辑决定了数据类型.当用户提出在某一界面上添加/移除一个数据信息时,或者需要保存更多的数据信息时,数据类型都会变化.当业务逻辑变化,假如(仅假如)个人信用等级和家属信用等级挂钩时,数据类型也会变化.我上面指的"数据类型"应该是class或record定义的复合类型.
      

  18.   

    我说的是:一个数据库,可能支持给 多种应用,多种不同的程序(asp/jsp/delphi...)
    其它使用到这个表的应用要求增加字段,而暂时不影响另外的某些应用,是很正常的
      

  19.   


    一年没更新DELPHI..原来还支持C++的模板来了...
      

  20.   

    hibernate一张表对应一个配置文件和对象文件一个dao文件,如果delphi也写类似的东西就是一个pas文件一