Attributes in Delphi are just classes, when you write a language construct with an attribute, what you do is instantiate a class and link it to the construct for use by RTTI. So you can avoid the interface (which in fact will only be for you headache) through an ancestor, as follows:
TFieldAttribute = class(TCustomAttribute)
private
FName: string;
FisPk: Boolean;
public
constructor Create(const aName: string; aIsPk: Boolean=False);
property Name:string read FName write FName;
property IsPk: Boolean read FIsPk write FIsPk;
end;
TFieldStringAttribute = class(TFieldAttribute)
end;
TFieldIntegerAttribute = class(TFieldAttribute)
end;
And so for all attributes, however, I do not understand why you need specific attributes by type, since Rtti already gives you the typing of each property. In your place I would only have the ancestral attribute ( TFieldAttribute
) to identify each of the mapped properties and would use the type of that property itself to map to your persistence medium.
Now, if you have cases where there are different types between the Delphi property and the column in the database, then what you can do is create one more parameter in the attribute to say this. For example:
TFieldAttribute = class(TCustomAttribute)
private
FName: string;
FColumnType: string
FIsPk: Boolean;
public
constructor Create(const aName: string; aIsPk: Boolean=False); overload;
constructor Create(const aName, aColumnType: string; aIsPk: Boolean=False); overload;
property Name:string read FName write FName;
property ColumnType: string read FColumnType write FColumnType;
property IsPk: Boolean read FIsPk write FIsPk;
end;
In particular, I would have a proper PK attribute. Here it would be:
TFieldAttribute = class(TCustomAttribute)
private
FName: string;
FColumnType: string
public
constructor Create(const aName: string); overload;
constructor Create(const aName, aColumnType: string); overload;
property Name:string read FName write FName;
property ColumnType: string read FColumnType write FColumnType;
end;
TPrimaryKeyAttribute = class(TFieldAttribute)
end;
Then in your code you need to test the attribute type using the is
operator. In the case of a person type class (typical example) would be:
TPessoa = class
private
[PrimaryKey('Id')]
FId: Long;
[Field('Nome')]
FNome: string;
[Field('Dt_Nasc', 'VARCHAR')]
FNascimento: TDateTime;
public
property Id: Long read FId;
property Nome: string read FNome write FNome;
property Nascimento: TDateTime read FNascimento write FNascimento;
end;
I imagine this will serve you!