![]() |
Funcion Get usando RTTI
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.
por ejemplo: 1. Creo una clase TCliente
2. Creo una function con parametros del nombre de la Tabla y el numero del registro. por ejemplo la tabla se llama Cliente y el Id es el numero 1, estos datos los pongo cuando invoco la función:
aquí les paso la funcion GetObject que es la quiero implementar
Como comentaba en lineas arriba no se como modificar los atributos del objeto Obj para poder devolver el objeto con todos sus valores. todo esto lo quiero hacer para cualquier tabla y cualquier tipo de objeto, para esto debo indicar que si creo una tabla Kardex también creo una clase TKardex en un .pas que se llamaría Modelo_Kardex, ese es un standard que sigo. Les pido me den una mano para poder solucionar este problema, este metodo me serviria para extraer cualquier objeto de cualquier tabla. Muchas gracias de antemano por leer esta consulta y gracias por su tiempo. Saludos, Javier Villa. |
Hola, Javier.
Sin afán de molestar, veo un poco vago tu avance de esa implementación, aunque celebro cada vez que alguien se pone a trabajar con los valiosos recursos de la RTL. Por lo visto quieres implementar algo similar al "streamming" de Delphi o más formalmente persistencia de objetos: lectura/escritura de instancias de clases en un medio de almacenamiento. No es que sea imposible, hay varias formas de conseguirlo, pero primero debes superar barreras más elementales. Por ejemplo, al hacer esto: Cita:
Quizá deberías, por un lado, estudiar y practicar un poco más la POO en Delphi. Y, por otro, compartir cómo llegaste a la conclusión de que necesitas implementar persistencia de objetos en tu aplicación. Claro, si te nace darnos a conocer el panorama general de tu idea. Saludos. :-) |
Cita:
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
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:
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
Para llegar a estom a grosso modo debes definir una calse para el atributo:
Posteriomente en tu "getObjeto(pObjeto: TObject)" debes revisar estas properties:
la asignacion de valores , que es lo que creo que quieres la harias con
SetField y setProp:
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. |
Tal como han dicho, estás incursionando en un ORM o un "Framework de Persistencia".
La idea es interesanta, pero a mi entender te falta completar "la pieza" importante. Tienes: 1) La clase TCliente. No se si realmente la tienes así definida o simplemnte la has puesto así aquí para simplificar, pero un primer consejo es que todas tus clases de "persistenca" deriven de una clase base (si no lo tienes así). 2) Tienes la tabla de CLIENTE con sus campos. 3) Tienes la pieza que te "convierte" un elemento de Entidad-Relacion a un Objeto persistente. A esta clase, a mi entender, le falta información. Está claro que el resultado de la ejecución (en tu caso) debe ser un objeto TCliente. De alguna forma esta función debe llegar a conocer la referencia a la clase TCliente, de forma que el objeto que se cree no sea utilizando TObject sino la referencia a esa clase.
http://docwiki.embarcadero.com/RADSt...ass_References |
Me han dado una buena luz para continuar
Muchas gracias por todas las respuestas.
Quiero comentarles que defino en archivo .pas las clases que defino, por ejemplo: Modelo_Cliente.pas. Aquí defino las clase TCliente. en otro archivo .pas llamado Cx_Cliente, defino funciones que me devuelvan valores consultando la base de datos, por ejemplo:
tambien tengo procedimientos almacenados de sql que lo invoco de esta manera:
este procedimiento lo repito para cualquier tabla por ejemplo para las ventas tengo una clase TVenta guardado en un archivo Modelo_Venta, ademas de los procedimientos y funciones en un archivo Cx_Venta donde me conecto a la base de datos y hago consultas y modificaciones a la tabla venta. Lo que quiero hacer es lo mismo pero un solo archivo donde pueda invocar los valores de cualquier tabla, es decir si es Cliente, Venta, etc, pero usando los objetos pertinentes. entonces hago un GetObject(Id: integer; TableName: String): TObject; y me devuelve un objecto de tipo TObject. quiero volver agradecer por su tiempo y ojala me puedan ayudar a realizar esta operación, que me ahorraría muchas lineas de código al hacer cualquier proyecto. Saludos, Javier Villa. |
Cita:
Lo ideal sería que tuvieras un objeto que defina cada objeto de clase, Modelo_Cliente.pas (TCliente), Modelo_Venta.pas (TVenta),... y que tal como dices, puedas tener centralizado en un único lugar el procedimiento que recupera los campos de una tabla en el objeto correspondiente. Tal como lo tienes ahora, el problema es que, debes tener en algún sitio la correlación entre los campos de la tabla y las propiedades de cada objeto. como no la tienes en ningún sitio, implementas un procedimiento por cada una de esas parejas (Cx_Cliente, Cx_Venta,...). Creo que puedes conseguir eso, en la propia clase TCliente, TVenta,... utilizando RTTI y atributos. De esa forma en un único lugar (procedimiento/función) podrás cargar los campos de la tabla en el objeto relacionado. Sería algo así:
El procedmiento:
Definido en la clase base (TBaseObject) debería poder acceder al atributo de cada clase (AttTableName) para conocer la tabla, y a las propiedades published del objeto vía RTTI. Para cada propiedad puedes conocer su atributo (AttrFieldName) para acceder al campo. De esta forma, podrías utilizar:
Bueno, más o menos esa es la idea. No se si me he explicado bien. Tienes información sobre cómo definir atributos aquí: http://docwiki.embarcadero.com/RADSt...tom_Attributes Cómo acceder a ellos en runtime: http://docwiki.embarcadero.com/RADSt...es_at_Run_Time |
Uso de RTTI - Solución encaminada
Muchas gracias por todas sus respuestas anteriores, me han dado mucha luz por donde debo ir, y la solución que hasta va bien es usar RTTI.
El objetivo es crear funciones clasicas como ObjectInsert(Obj: TObject):String, de iguakl manera un ObjectUpdate; ObjectDelete y GetObject:TObject; Para el caso de ObjectInsert, lo ha desarrolado un amigo y hasta funciona bien, pero lo estoy volviendo hacer para poder incorporar la opción de maestro/detalle y tambien que guarde en una tabla llamada BITACORA para poder controlar cualquier movimiento de los usuarios.
hay varias funciones que las estoy depurando, cuando las tenga lista se las paso, me parece super interesante estas funciones básicas para cualquier tabla. les reitero mi agradecimiento por el apoyo brindado. un fuerte abrazo. :) |
La franja horaria es GMT +2. Ahora son las 23:25:07. |
Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi