Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 05-01-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Lightbulb Error de declaracion de Clase Dinamica

Hola a todos los amigos del Foro.
Acudo a su gran experiencia y conocimiento para el problema que tengo, detallo todo para que me entiendan el problema y me puedan ayudar:

Código Delphi [-]
type
  TRubro = record
    cod_rubro : string[20];
    dsc_rubro: string[100];
  end;
type
  TEmpresa = record
    cod_empresa: string[20];
    nom_empresa : string[100];
    rubros: array[1..200] of TRubro;
  end;
type
  TEmpresas = class
  public
    RecordCount: Integer;
    Empresas: array[1..15000] of TEmpresa;
  end;

El problema que me esta generando es que cuando creo una variable de la clase: TEMPRESAS en ciertos momentos me esta devolviendo error ("Fuera de Memoria") quiero entender que eso es por los ARRAY qye estan definidos.

Quisiera me apoyen a evitar este error que no siempre me sale, si bajo el tamaño del array a un numero menor ya no me sale el error.

Preguntas:

1. La clase "TEmpresas" debe tener un arreglo dinámico ya que va a recibir una lista grande de empresas la cantidad no se sabe ya que es variable. entonces hay alguna forma de definir que el arreglo sea dinámico y cuando se tenga el número de registros se cree en base a ello. no sé si eso evitara que ya no salga el mensaje de ("Fuera de Memoria")?
2. Si ven el Record "TEmpresa" este también tiene un arreglo y quisiera saber si es posible también hacerlo dinámico, similar a lo comentado en el punto 1.
3. He definido así la clase por motivo que me va a llegar información desde un servicio rest(JSON) y tiene esta misma estructura y como luego la data de la clase guardara en un ClientDataSet, ¿no si es la mejor alternativa la que he elegido?

Por favor si hay algún amigo que me ayude a mejorar la clase o me indique ejemplos o donde está el error que estoy cometiendo le agradecería mucho.

Muchas Gracias por el apoyo

Saludos.
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #2  
Antiguo 05-01-2018
Avatar de movorack
[movorack] movorack is offline
Miguel A. Valero
 
Registrado: feb 2007
Ubicación: Bogotá - Colombia
Posts: 1.346
Poder: 20
movorack Va camino a la famamovorack Va camino a la fama
Hola!.

El Array si puedes definirlo como dinámico y luego establecer su tamaño

Cita:
Empezado por DelphiBasics
Código Delphi [-]
 var
   wishes : array of string;     //No se establecer el tamaño
 begin
   SetLength(wishes, 3);  // Se definie la capacidad a 3 elementos
 end;
__________________
Buena caza y buen remar... http://mivaler.blogspot.com
Responder Con Cita
  #3  
Antiguo 05-01-2018
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
Cita:
El problema que me esta generando es que cuando creo una variable de la clase: TEMPRESAS en ciertos momentos me esta devolviendo error ("Fuera de Memoria") quiero entender que eso es por los ARRAY qye estan definidos.
Cual es el codigo y el error exacto?

De todos modos yo te aconsejaria que te replantees el diseño, porque no se si tenga mucho sentido tener cargadas en memoria las 15,000 empresas, para las cuales ademas hay 200 rubros para cada una.

Otro problema puede ser porque los tipos record se alojan en la stack, y no en la heap como es el caso de las clases.

Respondiendo a las preguntas:

Cita:
1. La clase "TEmpresas" debe tener un arreglo dinámico ya que va a recibir una lista grande de empresas la cantidad no se sabe ya que es variable. entonces hay alguna forma de definir que el arreglo sea dinámico y cuando se tenga el número de registros se cree en base a ello. no sé si eso evitara que ya no salga el mensaje de ("Fuera de Memoria")?
Podes usar un arreglo dinamico, simplemente no tenes que declarar su tamaño. Hay que tener en cuenta que debes inicializar explicitamente el array, reservando la memoria e indicando cuantos elementos quere que tenga, por ejemplo:

Código Delphi [-]
var
  Empresas: array of TEmpresa;
begin
  // reservamos memoria para 20 empresas
  System.SetLength(Empresas, 20);
  // accedes por indice, 0-based
  Empresas[0].cod_empresa = 'blablabla';

  // podes redimensionarlo sin ningun problema. Ten en cuenta que es una operacion "costosa" ya que implica mover todo el arreglo
  // a una nueva posicion de memoria en donde quepa
  System.SetLength(Empresas, 30);
end;

De todos modos hay mejores alternativas que gestionan de manera automatica y de forma mucho mas eficiente un arreglo. La solucion mas adecuada para tu problema es usar una clase tipo lista, como TList<T>

Cita:
2. Si ven el Record "TEmpresa" este también tiene un arreglo y quisiera saber si es posible también hacerlo dinámico, similar a lo comentado en el punto 1.
Idem anterior. Podes tener variables en clases o records de tipo TList<T>, sin ningun problema. Ten en cuenta que son objetos y que debes inicializarlos antes de usarlos, y destruirlos cuando ya no los uses mas. En un record yo nunca pondria una variable que sea un objeto. Si queres mantener el tipo TEmpresas como un record, lo mas adecuado seria que uses un arreglo dinamico. Los arreglos dinamicos son liberados automaticamente de memoria (tienen contador de referencias, como los strings)

Para declarar una variable de tipo arreglo dinamico debes primero crear un tipo:

Esto no se permite (si no me falla la memoria)

Código Delphi [-]
type
  TEmpresa = record
    rubros: array of TRubro;
  end;

Esto si:

Código Delphi [-]
type
  TRubros = array of TRubro;
  TEmpresa = record
    rubros: TRubros;
  end;

De todos modos, yo prefiero utilizar genericos, y Delphi ya provee un tipo de arreglo dinamico generico

Código PHP:
type
  TEmpresa 
record
    rubros
TArray<T>; // si buscas la declaracion de TArray<T>, esta definido como TArray<T> = array of T; 
  
end
Cita:
3. He definido así la clase por motivo que me va a llegar información desde un servicio rest(JSON) y tiene esta misma estructura y como luego la data de la clase guardara en un ClientDataSet, ¿no si es la mejor alternativa la que he elegido?
No entendi muy bien la pregunta.. vas a recibir y almacenar toda esa informacion en las clases y despues volcarlas a un ClientDataSet? Y porque no volcar todo directamente al ClientDataSet? Por que lo queres pasar al ClientDataSet?
Responder Con Cita
  #4  
Antiguo 05-01-2018
jorge82 jorge82 is offline
Baneado
 
Registrado: jun 2005
Ubicación: Mérida, Yucatán, México
Posts: 75
Poder: 19
jorge82 Va por buen camino
Para declarar un array dinámico solo tienes que declararlo de la siguiente forma:

Código Delphi [-]
rubros: array of TRubro // sin el tamaño

y después para asignarle el tamaño y liberarla:
Código Delphi [-]
SetLength(rubros, 200); // 200 elementos
// Utilizar el array...
Finalize(rubros); // Para liberar la memoria, equivalente a SetLength(rubros, 0);
__________________
Un saludito.
Responder Con Cita
  #5  
Antiguo 05-01-2018
Avatar de movorack
[movorack] movorack is offline
Miguel A. Valero
 
Registrado: feb 2007
Ubicación: Bogotá - Colombia
Posts: 1.346
Poder: 20
movorack Va camino a la famamovorack Va camino a la fama
En este caso, como habla de recibir los datos desde un JSON, es posible que esté usando una librería que al traducirlos, use Records para almacenar las estructuras que recibe. Al menos manejando SuperObject debí manejarlo así.

Código Delphi [-]
function JsonStringToObject < T > (JSONString: string): T;
  var
    ctx: TSuperRttiContext;
    jso: ISuperObject;
begin
  {$TYPEINFO ON}
  {$METHODINFO ON}
  ctx := TSuperRttiContext.Create;
  try
    jso := SO(JSONString);
    Result := ctx.AsType(jso);
  finally
    FreeAndNil(ctx);
    {$TYPEINFO OFF}
    {$METHODINFO OFF}
  end;
end;
__________________
Buena caza y buen remar... http://mivaler.blogspot.com
Responder Con Cita
  #6  
Antiguo 05-01-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Muchas Gracias amigos movorack, AgustinOrtu, jorge82 por sus respuestas.
Se me olvido comentar que el sistema que estoy dando mantenimiento esta usando Delphi 6 y Veo que hay sugenrencias que se pueden aplicar en versiones mas actualizadas.

Disculpen por olvidar comentar un detalle importante de la version del Delphi y por ello estoy usando la libreria uLkJSON.pas ya que tambien veo que las versiones mas actuales manejan mejor los servicios REST.

quiero agregar una pregunta mas que me esta pasando con dicha libreria y capaz alguien ya le haya pasado dicho problema:

Al momento de usar los objetos LkJSON si bien no tengo problemas en aplicar la estructura JSON a sus objetos. Al momento de obtener un valor y este tiene un caracter acentuado (á, é, í, ó, ú) me esta devolviendo '' vacio. en la estructura JSON si esta el valor con los caracteres especiales. alguna sugerencia para que permita obtener el valor correcto y con los caracteres que viene en el JSON.

Estaba pensando hacer una funcion que reemplace esos caracteres por codigos validos en la estructura JSON antes de acloparlo a la libreria LkJSON y al asignarles a un Field cambiarlo por el caracter correcto.

alguna otra solucion para esta ultima pregunta?
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #7  
Antiguo 05-01-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Arrow

Disculpen mi poca experiencia en Delphi me pueden ayudar a aclara como seria la forma correcta:

Código Delphi [-]
TRubro = record
  cod_rubro : string[20];
  dsc_rubro: string[100];
end;
type
  TRubros = class
  public
    RecordCount: Integer;
    Rubros: array of TRubro;
  end;
...

var
  ListRubros : TRubros;
Begin
  ListRubros:= TRubros.Create;

¿Como le asigno a ListRubros.Rubros el espacio en memoria mediante SetLength(XXX, RecordCount)?
Como deberia ser la definicion correcta?

Muchas Gracias por sus comentarios.
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #8  
Antiguo 05-01-2018
jorge82 jorge82 is offline
Baneado
 
Registrado: jun 2005
Ubicación: Mérida, Yucatán, México
Posts: 75
Poder: 19
jorge82 Va por buen camino
Cita:
Empezado por Maniches Ver Mensaje
Disculpen mi poca experiencia en Delphi me pueden ayudar a aclara como seria la forma correcta:

Podría ser así:

Código Delphi [-]
TRubro = record
  cod_rubro : string[20];
  dsc_rubro: string[100];
end;
type
  TRubros = class
  public
    RecordCount: Integer;
    Rubros: array of TRubro;
  end;
...

var
  ListRubros : TRubros;
Begin
  ListRubros:= TRubros.Create;

¿Como le asigno a ListRubros.Rubros el espacio en memoria mediante SetLength(XXX, RecordCount)?
Como deberia ser la definicion correcta?

Muchas Gracias por sus comentarios.
Código Delphi [-]
SetLength(ListaRubros.Rubros, 200);
//...
Finalize(ListaRubros.Rubros);
__________________
Un saludito.
Responder Con Cita
  #9  
Antiguo 06-01-2018
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola.

Si tu intención es manejar un caudal medianamente importante de datos en memoria, una buena opción es usar TClientDataSet, v.gr.:
Código Delphi [-]
...
procedure TForm1.FormCreate(Sender: TObject);

  procedure CreateCol(CDS: TClientDataSet; const fldName: string;
    const fldType: TFieldType; const fldSize: Integer = 0;
    const fldReq: Boolean = False);
  var
    fd: TFieldDef;
  begin
    fd := CDS.FieldDefs.AddFieldDef;
    fd.DataType := fldType;
    fd.Name     := fldName;
    fd.Size     := fldSize;
    fd.Required := fldReq;
  end;

var
  cdRub, cdEmp: TClientDataSet;  
begin
  cdRub := ClientDataSetRubro;
  cdEmp := ClientDataSetEmpresa;

  // Rubros
  cdRub.Close;
  cdRub.FieldDefs.Clear;
  CreateCol(cdRub, 'ID', ftInteger);
  CreateCol(cdRub, 'COD_RUBRO', ftString, 20);
  CreateCol(cdRub, 'DSC_RUBRO', ftString, 100);
  cdRub.CreateDataSet;
  cdRub.Open;

  // Empresas
  cdEmp.Close;
  cdEmp.FieldDefs.Clear;
  CreateCol(cdEmp, 'ID', ftInteger);
  CreateCol(cdEmp, 'COD_EMPRESA', ftString, 20);
  CreateCol(cdEmp, 'NOM_EMPRESA', ftString, 100);
  CreateCol(cdEmp, 'RUBRO_ID', ftInteger);  // referencia a ClientDataSetRubro.ID
  cdEmp.CreateDataSet;
  cdEmp.Open;
end;
...
De ese modo, TDataSource mediante, podras conectarle componentes data-aware y aprovechar sus beneficios como si se tratase de una bd en disco.

Por motivos de claridad he creado los campos en tiempo de ejecución pero lo podes hacer desde el Fields Editor en tiempo de diseño.

Este enlace te podría resultar útil: La potencia de los TClientDataSet

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #10  
Antiguo 06-01-2018
Avatar de Maniches
Maniches Maniches is offline
Miembro
 
Registrado: nov 2012
Ubicación: Lima - Perú
Posts: 67
Poder: 12
Maniches Va por buen camino
Smile

Gracias por tu informacion y sugerencia amigo ecfisa.
En realidad estaba complicandome ya que previo a lo que sugieres estaba creando RECORD y CLASS para almacenar la Data que luego lo incluia en un ClienDataSet.

Mejor desde un inicio planteo las estructuras en ClienDataSets y sus referencias y poblar directamente al CDS.

Muchas Gracias y ese va a ser el mejor camino ya que los CDS es un buen Objeto para manipular data.

Entre mis ultimas respuesta hice otra pregunta amigo con respecto a la libreria uLkJSON.pas no se si te ha pasado o me sugieres alguna forma para solucionar el problema que me esta ocurriendo.

Muchas Gracias a todos del Foro por su apoyo y sugeriencias.

GRACIAS TOTALES!!!
__________________
Maniches
maniches@outlook.com
Responder Con Cita
  #11  
Antiguo 06-01-2018
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
El problema de los acentos posiblemente sea por unicode. Como realizas la peticion/lectura de los datos?
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Error con clase utilitaria andresenlared JAVA 0 10-10-2013 01:03:33
Como obtener propiedad de una clase que está en una bpl dinámica? AFilth Varios 14 07-03-2007 18:04:04
Tengo un problema de un Error en la declaración de variables Robert01 Varios 4 03-03-2007 06:45:50
error clase no registrada samame Varios 2 21-04-2004 18:49:49
Me da error en la clase pprinterinfo2 fanon Impresión 7 28-05-2003 20:04:59


La franja horaria es GMT +2. Ahora son las 11:42:34.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi