Cita:
Empezado por javicho_villa
Buenos dias con todos, siempre es un gusto contactarlos, en esta oportunidad estoy tratando de hacer una función generica Get para que me devuelva un objeto de cualquier tipo a traves de una consulta con un Query.
|
Es una iniciativa interesante, en mi opinión es un inicio hacia un ORM, lo cual no es algo tan sencillo de implementar,y menos si no se trabaja con una concepción mas orientada a objetos, es decir el get es solo una parte de todo el proceso.
Me llama la atención lo que haces con el prefijo i para identificar las propiedades del objeto, o el mismo hecho de que la. En lugar de eso, te invito a que revises la documentación asociada a
TCustomAttribute
es la forma como puedes etiquetar tus clases, métodos, propiedades y darles un tratamiento.
Por ejemplo
Código Delphi
[-]
[TMyORMField('GEN_CLIENTES')]
TCliente = Class(TObject)
Private
Public
end;
Con esto, puedes indicarle a tu sistema que la clase definida tiene un atributo de tipo TMyORMField (creado por ti) que indica algo, en este caso tu decides que te va a representar el nombre de la tabla en la base de datos. con esto, tu clase y tu tabla pueden llamarse diferente.
De igual forma puedes agregar atributos a tus "Fields" y "properties", asi:
Código Delphi
[-] [TMyORMField('GEN_CLIENTES')]
TCliente = Class(TObject)
Private
Public
[TMyORMField('CLI_RUT')]
RUT: String;
[TMyORMField('CLI_ID',True,True)]
property Id_Cliente:Integer read FId_Cliente write FId_Cliente;
[TMyORMField('CLI_RAZONSOCIAL')]
property RazonSocial:String read FRazonSocial write FRazonSocial;
Property FechaConstitucion: TDateTime read FFechaConstitucion write FFechaConstitucion
[TMyORMField('CLI_RAZONSOCIALCORTA')]
property RazonSocialCorta:String read FRazonSocialCorta write FRazonSocialCorta;
end;
Mira que aqui utilizo el mismo atributo TMyORMField (podrian ser diferentes), con la diferencia que uno opera sobre la clase, indicando el nombre de la tabla y el otro indica el nombre del campo y otros datos.
Fijate tambien que los atributos pueden ir sobre properties o sobre fields.
En el caso del ID_Cliente, recibe dos parametros mas de tipo boleano (o cualquier tipo), tu decides que interpretación le puedes dar, por ejemplo, el primero podria indicar si es un campo requerido dentro de tu tabla y el segundo si es parte de la llave primaria.
Otra opcion es utilizar multi-atributos para indicar esto
Código Delphi
[-][TMyORMField('CLI_RAZONSOCIAL')]
[TMyORMFieldFlags('ESLLAVE')]
Property Id_Cliente
Para llegar a estom a grosso modo debes definir una calse para el atributo:
Código Delphi
[-]TMyORMField = class(TCustomAttribute)
private
FIsKeyField: Boolean;
FFieldName: String;
FIsNotNull: Boolean;
procedure SetFieldName(const Value: String);
procedure SetIsKeyField(const Value: Boolean);
procedure SetIsNotNulll(const Value: Boolean);
public
Property FieldName: String read FFieldName write SetFieldName;
Property IsNotNull: Boolean read FIsNotNull write SetIsNotNulll;
Property IsKeyField: Boolean read FIsKeyField write SetIsKeyField;
Constructor Create(pFieldName: String;
pIsNotNulll: Boolean = False;
pIsKey: Boolean = False
); reintroduce;
Procedure Inicializar; end;
Posteriomente en tu "getObjeto(pObjeto: TObject)"
debes revisar estas properties:
Código Delphi
[-]function TMyORMEngine.getAtributosObjeto: Boolean;
var ctx : TRttiContext;
rt : TRttiType;
prop : TRttiProperty;
xfield: TRttiField;
Attr: TCustomAttribute;
vCampos: TCampo; begin
Result:= False;
if not Assigned(Objeto) then exit;
FTabla:='';
LimpiarCampos;
Try
ctx := TRttiContext.Create();
rt := ctx.GetType(Objeto.ClassType);
for prop in rt.GetProperties() do
for Attr in prop.GetAttributes() do
if Attr is TMyORMField then
Begin
Result:= True;
vCampos:= TCampo.Create;
vCampos.PropType:= ptProperty;
vCampos.Name:= prop.Name;
vCampos.FieldName:= (Attr as TMyORMField).FieldName;
vCampos.IsNotNull:= (Attr as TMyORMField).IsNotNull;
vCampos.IsKeyField:= (Attr as TMyORMField).IsKeyField;
FlstCampos.Add(vCampos);
End;
for xfield in rt.GetFields do
for Attr in xfield.GetAttributes do
if Attr is TMyORMField then
Begin
Result:= True;
vCampos:= TgtsCampo.Create;
vCampos.PropType:= ptField;
vCampos.Name:= xfield.Name;
vCampos.FieldName:= (Attr as TMyORMField).FieldName;
vCampos.IsNotNull:= (Attr as TMyORMField).IsNotNull;
vCampos.IsKeyField:= (Attr as TMyORMField).IsKeyField;
FlstCampos.Add(vCampos);
End;
for Attr in rt.GetAttributes do
if Attr is TMyORMField then
begin
Result:= True;
FTabla:= (Attr as TMyORMField).FFieldName;
end;
Finally
ctx.Free;
End;end;
la asignacion de valores , que es lo que creo que quieres la harias con
Código Delphi
[-]procedure TMyORMEngine.AsignarPropiedades(pDataSet: TDataSet);
Var i:Integer;
vCampo: TgtsCampo;
begin
if (not Assigned(pDataSet)) or
(not pDataSet.Active) or
(pDataSet.IsEmpty) then
exit;
if not Assigned(Objeto) then
exit;
pDataSet.First; For i:=0 to pDataSet.FieldCount-1 do
begin
vCampo:= getCampoByFieldName(pDataSet.Fields[i].FieldName); if Assigned(vCampo) then
begin
if vCampo.IsKeyField then
Continue;
if vCampo.PropType = ptProperty then
SetPropValue(vCampo.Name, pDataSet.Fields[i].Value);
if vCampo.PropType = ptField then
SetFieldValue(vCampo.Name, pDataSet.Fields[i].Value);
end;
end;
end;
SetField y setProp:
Código Delphi
[-]procedure TMyORMEngine.SetFieldValue(pName: String; pValor: Variant);
var ctx : TRttiContext;
rt : TRttiType;
xfield: TRttiField;
begin
if not Assigned(Objeto) then
exit;
ctx := TRttiContext.Create();
Try
rt := ctx.GetType(Objeto.ClassType);
xfield := rt.GetField(pName);
if Assigned(xfield) then
xfield.SetValue(Objeto, TValue.From(pValor));
Finally
ctx.Free;
End;
end;
procedure TMyORMEngine.SetPropValue(pName: String; pValor: Variant);
var ctx : TRttiContext;
rt : TRttiType;
prop : TRttiProperty;
begin
if not Assigned(Objeto) then
exit;
ctx := TRttiContext.Create();
Try
rt := ctx.GetType(Objeto.ClassType);
prop := rt.GetProperty(pName);
if Assigned(prop) then
prop.SetValue(Objeto, TValue.From(pValor));
Finally
ctx.Free;
End;
end;
Lo anterior es un extracto de algunas pruebas que hice pensando tal vez en lo mismo que tu quieres, pero solo a manera de ejercicio... funcionó lo que hice, pero nunca lo implementé. Como te dije lo anterior es un "a grosso modo"
Con la clase TMyORMEngine, iban muchos, muchos metodos y propiedades, como la persistencia en la DB a partir de los datos obtenidos... o la asignacion de sentencias SQL custom (insert, update, delete),
Como te digo, GetObject es solo una tarea de todo lo que deberias organizar sobre este tema.