PDA

Ver la Versión Completa : diseño centralizado de datasets, aplicación BD grande, crear componentes dinámicos..


pvizcay
18-09-2007, 02:58:16
hola amigos del foro,

supongamos que tengamos una aplicación de base de datos (grande, firebird + mdo), con varios forms (que se crean dinámicamente, incluso duplicados) y que casi todos utilizan además varios datasets de "soporte" (para lookups, realizar tareas comunes, etc.).. lo que estoy intentando lograr es centralizar estos datasets lo más posible, cosa que si tengo q modificar algo lo tenga en un solo lugar.. además de tener un diseño más limpio..

entonces empezamos creando un DataModule y tirando los 20-25 datasets en el mismo, completando el sqltext, los fields, etc..

el primer punto es que si bien varios forms utilizan los mismo datasets, tienen que ser distintos en tiempo de ejecución (osea cada Form dinámico tiene que tener su propia copia del dataset), por lo tanto con crear un solo DataModule y linkear todos los forms dinámicos al mismo no estamos..

una posibilidad sería crear un DataModule para cada nuevo Form, lo cúal a mi entender sería un desperdicio de recursos (y ni hablar si abrimos todos los datasets..).. otra opción sería crear un DataModule por cada dataset.. ni hablar..

la solución a este problema sería crear un componente en tiempo de ejecución y luego asignarle las propiedades guardadas en el stream de datos del dataset en cuestión (almacenado en el DataModule "padre", que le setié las propiedades en tiempo de diseño)

lo que traté fue algo como:
var
ds: TMdoDataset;
begin
ds := TMdoDataset.Create(Self);
ds.Assign(DataModulePadre.dsXXXXX); << error
end

pero me da un error y obviamente porque la clase persistent define el método Assign con una llamada a un método q lanza una excepción solamente (osea está el método para que se complete en las clases derivadas).. en pocas palabras si queres copiar, tenes que hacer el override manual..

la pregunta es.. ¿alguien sabe como se logra lo que busco? o ¿un diseño que cumpla con lo q plantea el problema?

pd: tb se podría crear una función que te cree un dataset seteando todas las propiedades por código y te lo devuelva y usarlo por cada form dinámico que lo necesite, pero la gracia es aprovechar los diseñadores visuales de delphi me parece a mi..

pd2: cuando hablo de datasets puede entender, llamada un TMdoStoredProcedure o cualquier otro componente de datos que quiera reutilizar..

desde ya gracias!

Casimiro Notevi
18-09-2007, 19:09:56
Hola, creo que nadie ha respondido todavía porque no se entiende bien cuál es el problema al que quieres dar solución, ¿podrías explicarlo de otra forma?, gracias.

pvizcay
18-09-2007, 21:23:37
hola casimiro, grax por tu rpta.

me voy a explicar de otra forma..

básicamente quiero crear componentes en tiempo de ejecución pero con los valores de las propiedades de otros componentes que setié en tiempo de diseño..

ejemplifico, tengo un DataModule (DM1) y un Dataset (DS1) dentro (que sería mi template o base de donde quiero "clonar").. ahora tengo un Form que se crea dinámicamente que tiene que tener y usar una copia de ese DataSet (pero no la misma instancia):

FormCreate
var
DSDinamic: TMdoDataset;
begin
DSDinamic := TMdoDataset.Create(Self);

DSDinamic.Assign(DM1.DS1)
// ahora DSDinamic tendría q ser una copia de DM1.DS1 //
// uso DSDinamic.. //
end

ahora se entiende mejor? :)

saludos

Casimiro Notevi
19-09-2007, 09:06:11
Sí, sería una copia del otro. Y no olvides liberarlo al final: DSDinamic.Free

pvizcay
19-09-2007, 14:19:36
no se si no se entendió.. el código ese no funciona..

Casimiro Notevi
19-09-2007, 15:13:13
Pues asi no sabría qué decirte, ¿has probado con owner en lugar de self?:
DSDinamic := TMdoDataset.Create(owner);

pvizcay
19-09-2007, 15:39:05
si.. el problema no pasa por ahi, el método Assign es de la clase TPersistent pero la misma no define como se realiza la operación (y con razón, no puede saber como copiar clases que van a descender de ella), simplemente lanza una excepción que es de la q hablo en el primer post

en pocas palabras la clase dataset mdo no lo define, eso lo puse más como ejemplo...

yo lo que quiero es usar la información que esta en el .DFM para crear componentes de forma dinámica, sin tener que duplicar todo el módulo completo (y sin tener que asignar las propiedades a manopla) ahora se entiende mejor?

Casimiro Notevi
19-09-2007, 21:36:14
Entonces creo que lo que quieres es algo así:

procedure TForm1.bt1Click(Sender: TObject);
var
Q2 : TIBDataSet;
begin
try
Q2 := TIBDataSet.Create(Owner);
Q2 := Q1 ; // .Assign(Q1);
ShowMessage(Q2.SelectSQL.Text);
finally
FreeAndNil(Q2);
end;
end;

Pruébalo, te lo digo de memoria, no tengo un delphi aquí.



Edito: Ahora que lo pienso, esa solución no sirve, fallaría la segunda vez que lo asignaras porque al igualar Q2 a Q1, al hacer el FreeAndNil(Q2) también se lo estaría haciendo a Q1.
Mejor déjame que saque un poquito de tiempo mañana en el trabajo y lo miro.

maeyanes
19-09-2007, 22:08:15
Podrías hacer uso de la RTTI...

Checa este artículo, ahí viene un projecto que tiene un procedimiento llamado CopyObject

http://www.blong.com/Conferences/BorConUK98/DelphiRTTI/CB140.htm


Saludos...

axesys
20-09-2007, 02:30:40
Yo tengo una forma base con una funcion que me crea los datamodulos


interface
type
TDataModuleClass = class of TDataModule;
TfrmBase = class(TForm)
protected
function CrearDataModulo(sNombre: string): TDataModule;
end;

implementation

function TfrmBase.CrearDataModulo(sNombre: string): TDataModule;
begin
sNombre:= StringReplace(sNombre, 'frm', 'dm', []);
Result:= TDataModuleClass(GetClass(sNombre)).Create(Self)
end;


Luego en la forma que ocupa crear el datamodulo por ejemplo un catalogo base tengo


interface
type
TfrmCatalogo = class (TfrmBase)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FCatalogo: TdmCatalogo;
end;

implementation

procedure TfrmCatalogo.FormCreate(Sender: TObject);
begin
inherited;
FCatalogo:= CrearDataModulo(ClassName) as TdmCatalogo
end;

procedure TfrmCatalogo.FormDestroy(Sender: TObject);
begin
inherited;
FreeAndNil(FCatalogo)
end;


Ademas tengo un datamodulo base para los catalogos


type
TdmCatalogo = class(TDataModule)
dtsCatalogo: TIBDataSet;
dsCatalogo: TDataSource;
end;


Despues solo heredo un frmCatalogo y un dmCatalogo para cada catalogo que voy hacer y les pongo el mismo nombre por ejemplo frmCatalogoArticulos y dmCatalogoArticulos con eso ya se crean solos

Ademas pongo en initialization de cada uno que heredé que se registre su clase por ejemplo RegisterClass(TfrmCatalogoArticulos) y RegisterClass(TdmCatalogoArticulos)

Espero que te pueda servir saludos

Al González
20-09-2007, 08:21:43
¡Hola a todos!

Entiendo perfectamente tu planteamiento Pvizcay. Quizá esto no represente ninguna solución para ti, pero en este otro hilo (http://www.clubdelphi.com/foros/showthread.php?t=46650) hablo de cierta característica que le agregué a uno de mis componentes para lograr algo muy similar a lo que tú buscas y debido a la misma inquietud.

Para lograrlo hice uso de las funciones de RTTI que sugiere Maeyanes (las cuales se encuentran en la unidad TypInfo.pas). El resultado es que ahora puedo copiar las propiedades publicadas de cualquier objeto y eso me permite, por ejemplo, clonar el conjunto de datos (data set) que se le haya asignado en tiempo de diseño a un TDataSource. De tal manera que ahora defino en tiempo de diseño un sólo data set por entidad de datos, independientemente de las diferentes formas donde se utilice (y cómo se utilice) de manera simultánea.

Propiedad DataSetCloned:
http://img230.imageshack.us/img230/6788/datasetclonedrf8.jpg (http://imageshack.us)

En las funciones de TypInfo.pas está la solución, aunque requiere de una considerable cantidad de trabajo.

Un abrazo simplificado.

Al González. :)

pvizcay
22-09-2007, 00:04:03
bueno primero gracias a todos

con las cosas que leí aca y otras que encontré por mi cuenta ya "veo" por donde encarar la solución.. cuando lo tenga todo armadito lo posteo de vuelta para ver que les parece

saludos!

Casimiro Notevi
22-09-2007, 00:24:23
Pues sería muy interesante, no recordaba esa aportación de Al González, pero es muy, muy interesante.

Neeruu
12-10-2011, 22:13:45
Hola pvizcay, quería saber si pudiste resolver de alguna manera la centralización de DataSet...

Yo empece a caminar el mismo camino de dudas que aquí se menciona...

En un principio opte por crear una instancia del modulo de datos por cada Formulario que instan cio, pero esta forma de trabajo mas allá de los recurso que consume ( que aunque no me veo afectado por ello se que es un punto a mejorar) , me genera un tiempo de retardo en la apertura de los formularios debido a la conexión de la base de datos.

Ejemplo:

Creo un Formulario
En el Evento create del Form, es donde instancio el Modulo de datos y realizo la conexión de ese modulo con la base de datos,
generando un tiempo extra a la hora de crear el formulario, debido al tiempo que utiliza el componente en conectar con la DB.


Fue por todo lo esto que se me ocurrió la posibilidad de instan ciar un modulo de datos, con su conexión establecida, y luego por cada formulario instan ciado, solo obtener una copia de ese modulo de datos instan ciado, o se una copia/clon de ese objeto data-module.

Por eso quería saber si tenias alguna solución.??


Por otro lado, encontré lectura sobre los componentes MagiaData de Al Gonzalez, pero no puedo encontrarlos (No se si están para descargarlos en algún lugar, si son pagos o no...)

Saluda Atte Neeruu!!! :)

Al González
13-10-2011, 03:18:29
Por otro lado, encontré lectura sobre los componentes MagiaData de Al Gonzalez, pero no puedo encontrarlos (No se si están para descargarlos en algún lugar, si son pagos o no...)

Qué tal amigos. Sí que ha pasado tiempo desde que se abrió este hilo.

Cuando dirigía una pequeña empresa, Magia Data era un paquete de componentes de paga. Ese tipo de licencia y la empresa misma nunca me convencieron del todo, experimentaba constantemente la sensación de estar en el lugar equivocado.

El año pasado me comprometí a liberar ésta y otras bibliotecas bajo una licencia open source, y lo único que me ha detenido es el deseo de pulirlas un poco primero. Sin embargo, como eso me ha significado una labor para la que no encuentro mucho tiempo disponible que digamos, hoy he decidido subir al FTP (http://www.terawiki.clubdelphi.com/Delphi/Componentes-Funciones/) del club el paquete de componentes Magia Data para Delphi 7 con su tradicional licencia.

Sé que no está permitido subir bibliotecas de paga, pero solicito a los moderadores que hagan una excepción en este caso, pues es mi intención que esté a disposición de todos sin costo alguno. Además el código fuente siempre lo he incluido. Si se quiere ver de otra manera, el precio es de $0.00 y para mayor facilidad puede ser descargada por quien guste desde el FTP de Club Delphi.

Prometo subir luego una versión de reemplazo que lleve una licencia de software libre explícita.

De antemano gracias y que de algo sirva esta aportación. :)

Al González.

P.D. En ella podrán encontrar el componente TMagiaDataSource con su propiedad DataSetCloned, a la que aludí en mensajes anteriores. No obstante, la clase con más características agregadas es TMagiaClientDataSet.

newtron
13-10-2011, 09:53:22
... el precio es de $0.00 ...

No sé amigo Al, ¿podemos negociar el precio? :p

Casimiro Notevi
13-10-2011, 11:41:34
Excelente aportación, gracias, Al.

Neeruu
13-10-2011, 15:55:36
Hola a todos......

Gracias Al González por el aporte!!!!

Pruebo las MagiaData, haber si es la solución que estoy buscando.....
Sino volveré por mas.....

Y mi pregunta sigue vigente: Hay alguna solución para lo expresado en este Post???


De nuevo gracias por el aporte Al González!!!!


Saluda Atte Neeruu!!! :)

fjcg02
13-10-2011, 19:18:23
Hola,
en la biblioteca GHFreebrary hay funciones que 'clonan' las propiedades de un objeto en otro.

Por ejemplo, si tienes un dataset, puedes crear otro que tenga sus mismas propiedades, además de todos sus eventos. Esta es una muy buena aportación de Al Gonzalez.

Más tarde lo miro en detalle y veo si tengo algún ejemplo.

Saludos

Neeruu
13-10-2011, 20:12:54
Lo que yo busco, y no se si realmente se puede hacer, es hacer lo siguiente:

En un DataModule tengo mi componente de conexión a la base de datos, que ya se encuentra una conexión establecida...

Si yo clono el objecto DataModule, el nuevo objeto, también debería tener la conexión a la base de datos establecida....

Saluda Atte Neeruu!!! :)

fjcg02
13-10-2011, 22:16:49
Ejemplo de llamada a la función

ghCopyDataSetProps (SQLDSClienteDesde, SQLDSClienteHasta,'Name',True,'');


Definición de la función - Sacada de GHFreebrary de Al González
{ Copy Data Set Props }
Procedure ghCopyDataSetProps (
Const Source, Dest :TDataSet; -- datasource origen, datasource Destino
Const Excludeds :String = ''; -- aqui ponemos las propiedad que queremos excluir , en el ejemplo el nombre
Const IncludeFields :Boolean = True; -- aqui indicamos si incluimos los campos o no en la copia
Const ExcludedFieldProps :String = '' -- aqui indicamos la propiedad de los campos que queremos excluir
);


Saludos
PD: Con el permiso del maestro. Un abrazo FREE

Al González
14-10-2011, 06:47:16
Muchas gracias Javier. :)

Bueno, primeramente decir que GH Freebrary viene dentro del paquete MagiaData7.zip que subí, y es que las clases TMagiaXXX llaman a algunas funciones "sueltas" de GH Freebrary. Por ejemplo, la propiedad DataSetCloned de TMagiaDataSource causa que internamente se llame a la función ghCloneDataSet de la unidad GHFData, misma unidad donde se encuentra también la función que amablemente ilustró fjcg02.

Neeruu, yo uso todo el tiempo la anterior característica. Es decir, coloco en uno o varios módulos de datos los data sets, pero pongo los data sources (TMagiaDataSource) en los formularios, activándoles a estos la propiedad DataSetCloned para que el formulario trabaje con una copia propia y local del conjunto de datos (un "clon"), y así darle mayor autonomía y evitar conflictos con otros formularios que también necesiten trabajar con el mismo conjunto de datos (ya sea simultáneamente o después en la misma sesión).

Así no tengo necesidad de crear varias instancias de un mismo módulo de datos y tampoco me preocupo de las propiedades que le establezco en tiempo de ejecución al conjunto de datos, porque es un clon que sólo afecta al ámbito del formulario y será destruido cuando el formulario se destruya también.

No obstante, comentas que sin usar nada de esto tienes demoras en las conexiones o aperturas de los conjuntos de datos. Entonces quizá convenga que primero revises por qué se tarda al abrir. Tal vez me equivoque, pero puede que estés trayendo muchos registros al activar alguna tabla o consulta. Creo que sería oportuno atacar primero ese problema. :)

Mencionas también que leíste ya algo sobre Magia Data. Probablemente se trata de este material (http://rescatandoadelphi.blogspot.com/2009/02/el-datasource-extendido-parte-1.html). De cualquier manera lo enlazo para ayudar a explicar de forma más clara por qué había necesidad de algo así y las ventajas que se obtienen con el componente.

fjcg02
14-10-2011, 12:32:31
Qué mejor que el padre de la criatura dando las explicaciones oportunas y precisas.

Al, ya que te has lanzado, ahora sería estupendo que nos ilustraras con algún ejemplo práctico de cómo usas todas esas piezas del puzzle que has confeccionado a lo largo del tiempo !!

Ya sabes que me gusta lo bueno, aunque desgraciadamente no tenga dinero para pagarlo. A veces sólo la esencia es suficiente ... y con gusto la disfruto !! ;)

Un abrazo

Al González
26-04-2012, 03:27:59
Al, ya que te has lanzado, ahora sería estupendo que nos ilustraras con algún ejemplo práctico de cómo usas todas esas piezas del puzzle que has confeccionado a lo largo del tiempo !!

Hola Javier, disculpa la demora de seis meses. :p

De momento esto puede servir: http://www.clubdelphi.com/foros/showthread.php?p=431019&posted=1#post431019

Ojalá hubiera un alma en este mundo que se animara (pero en serio) a echarme una mano con la biblioteca. :(

Saludos.

Al.

fjcg02
26-04-2012, 14:05:30
Nunca es tarde si la "picha" es buena !!!

jajajajajaj

PepeLolo
28-04-2012, 20:01:34
Una solución simple; almacena en la BBDD las SQL que necesites en tu aplicación. En una segunda tabla almacenas (Formulario, campo y idSQL).
En tu aplicación en el evento "oncreate" del formulario creas en tiempo de ejecución los objetos de datos y los "datasource" correspondientes y lo conectas al campo correspondiente de tu formulario. No necesitas clonar nada y simplificas. La próxima vez que necesites una SQL en otro formulario, ya lo tienes y solo tienes que incluir los datos en la tabla (formulario, campo, idsql):D