TRttiField - 如何投射课程

时间:2012-08-06 19:37:38

标签: delphi orm rtti

首先,这是我在这里的第一篇文章,所以我想先抱歉我的英语不好,其次我想对任何听起来可能听起来很愚蠢的问题感到抱歉

好吧,我正在尝试为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,我的祖先类,特别是在构造函数方法上,初始化每个字段(创建),所以我不需要在从祖先继承的每个类中显式创建每个字段< / p>

1 个答案:

答案 0 :(得分:4)

调用AField is ThsORMColumnIntegerAField 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;     

这种方法的好处在于,从技术上讲,您根本不需要使用属性标记字段才能使其工作,但我怀疑您仍然希望将其用于其他目的。