3

まず第一に、これはここでの私の最初の投稿です。まず、下手な英語で申し訳ありません。次に、次のように聞こえるかもしれない愚かな質問をして申し訳ありません。

さて、私はMySQL、Delphi、および私がここで働いているチームに固有の独自のORMを作成しようとしていますが、方法がわからないいくつかのことに行き詰まっています。クラスの最終的な定義の上に投稿します。

    uses
      hsORM.Mapping,
      hsORM.Types;

    type
      [ThsORMTableMap('hscad_cadmunicipal')]
      TMunicipe = class(ThsORMTable)
      private
        { Private declarations }
        [ThsORMColumnPrimaryKeyMap('inscricaomunicipal')]
        Fid : ThsORMColumnPrimaryKey;

        [ThsORMColumnNullableMap('idlogradouro', varInteger)]
        Fidlogradouro : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('idbairro', varInteger)]
        Fidbairro : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('idestadocivil', varInteger)]
        Fidestadocivil : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('idnaturezaestab', varInteger)]
        Fidnaturezaestabelecimento : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('idnaturezajuridica', varInteger)]
        Fidnaturezajuridica : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('idagencia', varInteger)]
        Fidagencia : ThsORMColumnNullable;

        [ThsORMColumnMap('datacadastro')]
        Fdatacadastro : ThsORMColumnDate;

        [ThsORMColumnMap('nome')]
        Fnome : ThsORMColumnString;

        [ThsORMColumnNullableMap('nomefantasia', varString)]
        Fnomefantasia : ThsORMColumnNullable;

        [ThsORMColumnMap('tipopessoa')]
        Ftipopessoa : ThsORMColumnString;

        [ThsORMColumnNullableMap('numero', varInteger)]
        Fnumero : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('complemento', varString)]
        Fcomplemento : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('observacao', varString)]
        Fobservacao : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('telefone', varString)]
        Ftelefone : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('celular', varString)]
        Fcelular : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('fax', varString)]
        Ffax : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('sexo', varString)]
        Fsexo : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('email', varString)]
        Femail : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('responsavel', varString)]
        Fresponsavel : ThsORMColumnNullable;

        [ThsORMColumnNullableMap('contacorrente', varString)]
        Fcontacorrente : ThsORMColumnNullable;

        [ThsORMColumnMap('foto')]
        Ffoto : ThsORMColumnBlob;

        [ThsORMColumnMap('fornecedor')]
        Ffornecedor : ThsORMColumnBoolean;

        [ThsORMColumnMap('tipocredor')]
        Ftipocredor : ThsORMColumnString;

        [ThsORMColumnMap('ativo')]
        Fativo : ThsORMColumnBoolean;
      public
        { Public declarations }
        property id : ThsORMColumnPrimaryKey read Fid write Fid;
        property idlogradouro : ThsORMColumnNullable read Fidlogradouro write Fidlogradouro;
        property idbairro : ThsORMColumnNullable read Fidbairro write Fidbairro;
        property idestadocivil : ThsORMColumnNullable read Fidestadocivil write Fidestadocivil;
        property idnaturezaestabelecimento : ThsORMColumnNullable read Fidnaturezaestabelecimento write Fidnaturezaestabelecimento;
        property idnaturezajuridica : ThsORMColumnNullable read Fidnaturezajuridica write Fidnaturezajuridica;
        property idagencia : ThsORMColumnNullable read Fidagencia write Fidagencia;
        property datacadastro : ThsORMColumnDate read Fdatacadastro write Fdatacadastro;
        property nome : ThsORMColumnString read Fnome write Fnome;
        property nomefantasia : ThsORMColumnNullable read Fnomefantasia write Fnomefantasia;
        property tipopessoa : ThsORMColumnString read Ftipopessoa write Ftipopessoa;
        property numero : ThsORMColumnNullable read Fnumero write Fnumero;
        property complemento : ThsORMColumnNullable read Fcomplemento write Fcomplemento;
        property observacao : ThsORMColumnNullable read Fobservacao write Fobservacao;
        property telefone : ThsORMColumnNullable read Ftelefone write Ftelefone;
        property celular : ThsORMColumnNullable read Fcelular write Fcelular;
        property fax : ThsORMColumnNullable read Ffax write Ffax;
        property sexo : ThsORMColumnNullable read Fsexo write Fsexo;
        property email : ThsORMColumnNullable read Femail write Femail;
        property responsavel : ThsORMColumnNullable read Fresponsavel write Fresponsavel;
        property contacorrente : ThsORMColumnNullable read Fcontacorrente write Fcontacorrente;
        property foto : ThsORMColumnBlob read Ffoto write Ffoto;
        property fornecedor : ThsORMColumnBoolean read Ffornecedor write Ffornecedor;
        property tipocredor : ThsORMColumnString read Ftipocredor write Ftipocredor;
        property ativo : ThsORMColumnBoolean read Fativo write Fativo;
      end;

さて、すべての mysql データ型に対してそれぞれのクラスを定義しました。次にやりたいことは、RTTI を使用して、このフィールドに動的なすべてを作成することです。Delphiのクラスは明示的に作成する必要があり、それを回避しようとしているため、私のクラスThsORMTableを使用して動的なこの列を作成しています。例えば:

    ThsORMTable = class
      private
        { Private declarations }
        FTableName: string;
        procedure InitializeTable();
        procedure InitializeColumns();
      public
        { Public declarations }
        constructor Create();
        property TableName : string read FTableName write FTableName;
      end;

    { ThsORMTable }

    {$REGION 'Private'}

    procedure ThsORMTable.InitializeTable();
    var
      AContext : TRttiContext;
      AType : TRttiType;
      AAttribute : TCustomAttribute;
      AFound : Boolean;
    begin
      AContext := TRttiContext.Create();
      try
        AFound := False;
        AType := AContext.GetType(ClassType);
        for AAttribute in AType.GetAttributes do
          if(AAttribute is ThsORMTableMap) then
            begin
              FTableName := (AAttribute as ThsORMTableMap).TableName;
              AFound := True;
              Break;
            end;
        if not(AFound) then raise Exception.Create(ETableNotMapped);
      finally
        AContext.Free();
      end;
    end;

    procedure ThsORMTable.InitializeColumns();
    var
      AContext : TRttiContext;
      AType : TRttiType;
      AField : TRttiField;
      AFound : Boolean;
    begin
      AContext := TRttiContext.Create();
      try
        AType := AContext.GetType(ClassType);
        for AField in AType.GetFields do 
                    /**********************************************
                    here i want something like for example
                    if(AField is ThsORMColumnInteger) then
                      begin
                        (AField as ThsORMColumnInteger) := ThsORMColumnInteger.Create();
                    is this possible? im going to the wrong way?
                      end;
                    **********************************************/
      finally
        AContext.Free();
      end;
    end;

    {$ENDREGION}

    {$REGION 'Public'}

    constructor ThsORMTable.Create();
    begin
      try
        InitializeTable();
        InitializeColumns();
      except on Error : Exception do
        raise ThsORMTableInitialization.Create(Format(ETableInitializationError, [Error.Message]));
      end;
    end;

    {$ENDREGION}

しかし、どうやってもコンパイルエラーが発生します。皆さんが私を助けてくれることを願っています。有利なthx

更新:わかりにくかったことをお詫びします。もう一度やり直してください。私がやろうとしているのは、私の先祖クラスである ThsORMTable を介して、具体的にはコンストラクター メソッドで、すべてのフィールドを初期化 (作成) することです。そのため、この祖先から継承したすべてのクラスで、このフィールドのすべてを明示的に作成する必要はありません。

4

1 に答える 1

4

AField is ThsORMColumnIntegerand の呼び出しAField as ThsORMColumnIntegerは常に失敗します。これTRttiFieldは、から派生していないためThsORMColumnIntegerです。

ThsORMTableクラスの各フィールドで何を達成しようとしているのか正確には不明です。各フィールドの属性にアクセスするだけの場合は、実際のオブジェクト インスタンスを作成する必要はありません。たとえば、次のようになります。

uses
  ..., TypInfo;

procedure ThsORMTable.InitializeColumns();  
var  
  AContext : TRttiContext;  
  AType : TRttiType;  
  AField : TRttiField;  
  AAttribute : TCustomAttribute;
  AFound : Boolean;
begin  
  AContext := TRttiContext.Create();  
  try  
    AType := AContext.GetType(ClassType);  
    for AField in AType.GetFields do   
    begin
      // TRttiType.TypeData is private so have to use the TypInfo unit directly...
      TypeData := TypInfo.GetTypeData(AField.FieldType.Handle);

      if TypeData^.ClassType is ThsORMColumnInteger then
      begin
        for AAttribute in AField.GetAttributes do      
        begin
          if (AAttribute is ThsORMColumnMap) then      
          begin      
            // use (AAttribute as ThsORMColumnMap) as needed ...
            AFound := True;      
            Break;      
          end;
        end;      
        if (not AFound) then raise Exception.Create(EColumnNotMapped);      
      end;
    end;
  finally  
    AContext.Free();  
  end;  
end;  

更新:更新された情報に基づいて、列クラス タイプの設定方法に応じて、次のようなことができる場合があります。

type
  ThsORMColumn = class(...)
    //...
  end;

  ThsORMColumnClass = class of ThsORMColumn;

  //...

  ThsORMColumnInteger = class(ThsORMColumn)
    // ...
  end;

  //...

procedure ThsORMTable.InitializeColumns();     
var     
  AContext : TRttiContext;     
  AType : TRttiType;     
  AField : TRttiField;     
  AAttribute : TCustomAttribute;   
  AObj : ThsORMColumn;   
begin     
  AContext := TRttiContext.Create();     
  try     
    AType := AContext.GetType(ClassType);     
    for AField in AType.GetFields do      
    begin   
      if AField.FieldType.TypeKind = tkClass then
      begin
        // TRttiType.TypeData is private so have to use the TypInfo unit directly...   
        TypeData := TypInfo.GetTypeData(AField.FieldType.Handle);   
        if (not TypeData^.ClassType.InheritsFrom(ThsORMColumn)) then
          raise Exception.Create(...);         
        AObj := ThsORMColumnClass(TypeData^.ClassType).Create();         
        AField.SetValue(Self, Obj);
      end;   
    end;
  finally     
    AContext.Free();     
  end;     
end;     

このアプローチの良い点は、技術的には、フィールドに属性をタグ付けする必要がまったくないことです。

于 2012-08-06T20:47:28.643 に答える