Ir al contenido


Foto

Como pasan de la grilla(dataset) a un objeto de una clase


  • Por favor identifícate para responder
25 respuestas en este tema

#21 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 17 junio 2017 - 05:16

Continuando con el tema, codifique la misma interfaz y la implemente para la clase detalle, que agrega un objeto producto.


delphi
  1. TDetalle = class
  2. private
  3. Fproducto: Tproducto;
  4.  
  5. Fcantidad: Double;
  6. FbaseImp: Double;
  7. Fsubtotal: Double;
  8. Ftotal: Double;
  9. procedure Setcantidad(const Value: Double);
  10.  
  11. procedure SetbaseImp(const Value: Double);
  12. procedure Setsubtotal(const Value: Double);
  13. procedure Settotal(const Value: Double);
  14. procedure Setproducto(const Value: Tproducto);
  15.  
  16. public
  17.  
  18. property producto:Tproducto read Fproducto write Setproducto;
  19. property baseImp:Double read FbaseImp write SetbaseImp;
  20. property subtotal:Double read Fsubtotal write Setsubtotal;
  21. property total:Double read Ftotal write Settotal;
  22. property cantidad:Double read Fcantidad write Setcantidad;
  23. constructor NuevoDetalle(producto:Tproducto;cantidad:Double);
  24. procedure calcularBaseImp(precio:Double;alic:Double);
  25. destructor destroy;
  26. end;

El caso es que al agregar un producto tengo:


delphi
  1. if (Ecantidad.Text <> EmptyStr) then
  2. begin
  3.  
  4. cant:=StrToFloat(Ecantidad.Text);
  5. pr:=TProductoRepository.Create(ClientModule1.cdsprod,true);
  6. p1:=pr.getproducto();
  7.  
  8. d:=TDetalle.NuevoDetalle(p1,cant);
  9. d.calcularBaseImp(p1.precio,cant);
  10. dr:=TDetalleRepository.Create(ClientModule1.cdsdetallefactura,True);
  11. dr.Save(d);
  12.  
  13.  
  14. end
  15. else
  16. ShowMessage('ingrese cantidad');
  17.  
  18.  
  19.  
  20. end;

creo el detalle y cuando lo quiero guardar en el dataset con save tengo el problema de acceder por ejemplo al nombre del producto que esta dentro del detalle:

 

osea en la descripcion iria el valor del atributo nombre del objeto producto que es un atributo del objeto detalle:


delphi
  1. procedure TDetalleRepository.Save(const detalle:TDetalle);
  2. var
  3. RecIndex: Integer;
  4. begin
  5. if FindDetalle(Detalle, RecIndex) then
  6. begin
  7. DataSet.RecNo := RecIndex;
  8. DataSet.Edit;
  9. end
  10. else
  11. DataSet.Append;
  12. DataSet.FieldByName('cantidad').AsFloat := Detalle.Fcantidad;
  13. ShowMessage(detalle.Fproducto.Fnombre);
  14. DataSet.FieldByName('idproducto').AsInteger := Detalle.producto.Fidproducto;
  15. DataSet.FieldByName('descripcion').AsString:=Detalle.producto.nombre;
  16.  
  17. DataSet.Post;
  18. end;

lo mismo con el id y otros atributos. Pero esas lineas me tiran error, no se cual es la forma sintactica de acceder sino.

Me da un read of adress, error de lectura de memoria seria en las lineas:


delphi
  1. DataSet.FieldByName('idproducto').AsInteger := Detalle.producto.Fidproducto;
  2. DataSet.FieldByName('descripcion').AsString:=Detalle.producto.nombre;

Agradezco su ayuda


  • 0

#22 Delphius

Delphius

    Advanced Member

  • Moderadores
  • PipPipPip
  • 6.295 mensajes
  • LocationArgentina

Escrito 17 junio 2017 - 09:01

¿Podrías poner como está diseñada tu base de datos? Quisiera saber para que quieres grabar en el detalle info que ya está (y le pertenece) al producto.

Entiendo que se necesite del ID del producto para que al momento de guardar en la base de datos puedas hacer la relación entre la FK y PK.

¿Cuál es la relación que has establecido entre Detalle y Producto?

 

Ahora bien, ¿Cuál es la finalidad de por ejemplo, guardar la descripción del producto en el detalle? Si es realmente la descripción del producto esto le corresponde a el mismo guardarla. Esto te lo pregunto por esto:


delphi
  1. DataSet.FieldByName('descripcion').AsString:=Detalle.producto.nombre;

El error en:


delphi
  1. DataSet.FieldByName('idproducto').AsInteger := Detalle.producto.Fidproducto;

Puede deberse a que estás intentando acceder a un atributo privado (por lo del "F"). Voy a ponerme en plan Google... quizá quisiste decir "IDproducto". ;)  Alguna propiedad, o método Getter para acceder a dicho atributo.

 

Por otro lado, ¡cuidado con desafiar la ley de Demeter! Si bien no es pecado hacer esto:


delphi
  1. Detalle.Producto.Propiedad;
  2. Detalle.Producto.HacerAlgo;

Ten en cuenta que estás accediendo a estas desde una clase cliente que "consume" a la clase TDetalle. Me refiero a TDetalleRepository. Si es necesario acceder al producto desde el repositorio del detalle como vemos en el ejemplo de tu código una buena práctica es evitar que se siga hablando con extraños.

Implementa a la clase TDetalle métodos getters de interés para comunicarse con TProducto, y alguna otra clase con la que esté relacionada. Por ejemplo:


delphi
  1. Detalle.GetIDProducto;

Esto te evita acoplar a TDetalleRepositery con TProducto. Simplemente se lo pide al TDetalle y que sea ésta quien le regrese lo necesario.

 

Cuanto más lejos y con cuanto más "extraños" pretendas hacer "hablar" a dos clases más débil se hará tu diseño. La ley de Demeter nos advierte que una clase no debería comunicarse con alguien más allá de con quien está relacionada de forma directa.

 

Saludos,


  • 0

#23 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 17 junio 2017 - 09:33

No tengo una tabla de detalle en la bd..solo factura(ticket) y producto.Luego una tabla intermedia para relacionar de 1 ticket a varios productos en el msmo. La idea del detalle era para hacer el programa con poo.Ya que una factura es una lista de detalles..

 

Tengo


sql
  1. DROP TABLE IF EXISTS `producto`;
  2. CREATE TABLE `producto` (
  3. `idproducto` INT(11) NOT NULL AUTO_INCREMENT,
  4. `idcategoria` INT(11) DEFAULT NULL,
  5. `idsubcategoria` INT(11) DEFAULT NULL,
  6. `idmarca` INT(11) DEFAULT NULL,
  7. `precio` DECIMAL(10,2) DEFAULT NULL,
  8. `iva` DECIMAL(10,2) DEFAULT NULL,
  9. `pedir` tinyint(1) DEFAULT NULL,
  10. `nombre` VARCHAR(100) DEFAULT NULL,
  11. `preciofactb` DECIMAL(10,2) DEFAULT NULL,
  12. `ganancia` DECIMAL(10,2) DEFAULT NULL,
  13. `preciofacta` DECIMAL(10,2) DEFAULT NULL,
  14. PRIMARY KEY (`idproducto`),
  15. KEY `idsubcategoria` (`idsubcategoria`),
  16. KEY `idcategoria` (`idcategoria`),
  17. KEY `idmarca` (`idmarca`),
  18. CONSTRAINT `producto_ibfk_1` FOREIGN KEY (`idsubcategoria`) REFERENCES `subcategoria` (`idsubcategoria`) ON DELETE NO ACTION,
  19. CONSTRAINT `producto_ibfk_2` FOREIGN KEY (`idcategoria`) REFERENCES `categoria` (`idcategoria`) ON DELETE NO ACTION,
  20. CONSTRAINT `producto_ibfk_3` FOREIGN KEY (`idmarca`) REFERENCES `marca` (`idmarca`) ON DELETE NO ACTION
  21. ) ENGINE=InnoDB AUTO_INCREMENT=5234 DEFAULT CHARSET=utf8;


sql
  1. DROP TABLE IF EXISTS `ticket`;
  2. CREATE TABLE `ticket` (
  3. `CAE` VARCHAR(20) DEFAULT NULL,
  4. `idticket` INT(11) NOT NULL,
  5. `idcliente` INT(11) DEFAULT NULL,
  6. `numero` INT(11) DEFAULT NULL,
  7. `importe` DECIMAL(10,2) DEFAULT NULL,
  8. `fechae` DATE DEFAULT NULL,
  9. `horae` TIME DEFAULT NULL,
  10. `idsucursal` INT(11) DEFAULT NULL,
  11. `efectivo` DECIMAL(10,2) DEFAULT NULL,
  12. `vuelto` DECIMAL(10,2) DEFAULT NULL,
  13. `idtipo` INT(11) DEFAULT NULL,
  14. PRIMARY KEY (`idticket`),
  15. KEY `idsucursal` (`idsucursal`),
  16. KEY `idcliente` (`idcliente`),
  17. KEY `idtipo` (`idtipo`),
  18. CONSTRAINT `ticket_ibfk_1` FOREIGN KEY (`idsucursal`) REFERENCES `sucursal` (`idsucursal`) ON DELETE NO ACTION
  19. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Y luego:


sql
  1. DROP TABLE IF EXISTS `venta`;
  2. CREATE TABLE `venta` (
  3. `idticket` INT(11) DEFAULT NULL,
  4. `idproducto` INT(11) DEFAULT NULL,
  5. `cantidad` DECIMAL(10,2) DEFAULT NULL,
  6. `preciou` DECIMAL(10,2) DEFAULT NULL,
  7. KEY `idticket` (`idticket`),
  8. KEY `idproducto` (`idproducto`),
  9. CONSTRAINT `venta_ibfk_1` FOREIGN KEY (`idticket`) REFERENCES `ticket` (`idticket`),
  10. CONSTRAINT `venta_ibfk_2` FOREIGN KEY (`idproducto`) REFERENCES `producto` (`idproducto`)
  11. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;


  • 0

#24 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 831 mensajes
  • LocationArgentina

Escrito 17 junio 2017 - 09:57

Una de dos, un error EAccessViolation es cuando tenes una referencia en nil, o bien es una referencia que ya se libero de memoria (es decir, se ejecuto .Free) y le seguis mandando mensajes


  • 0

#25 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 17 junio 2017 - 01:44

Una de dos, un error EAccessViolation es cuando tenes una referencia en nil, o bien es una referencia que ya se libero de memoria (es decir, se ejecuto .Free) y le seguis mandando mensajes

Definitivamente, lo segui con F9. Y el producto lo crea, se ven los valores de los atributos como estan en la bd. Pero el atributo producto de la clase detalle figura nil. No se porque lo pasa como nil

 

Ya esta, tenia mal el constructor de la clase detalle.

Ahora me falta modificar el metodo save por si se pasa dos veces el mismo articulo sumar la cantidad


  • 2

#26 giulichajari

giulichajari

    Advanced Member

  • Miembros
  • PipPipPip
  • 477 mensajes

Escrito 18 junio 2017 - 06:20

El unico problema con la grilla de  detalle de la factura es que no muestra el nombre del producto, osea la descripcion, es un cvampo string, con los otros campos ni un problema:

Quizas no necesite los aggregates del clientdataset ya que hice lo siguiente:


delphi
  1. procedure TDetalle.calculos();
  2. begin
  3. Setsubtotal(producto.Fprecio * cantidad);
  4. SetbaseImp(Fsubtotal * producto.Fiva/100);
  5. Settotal(subtotal + baseImp);
  6.  
  7. end;

calculo el subtotal bruto, luego la bsae imponible y sumo para obtener el total, esto lo tenia en el afterpost con campos agreggates


delphi
  1. procedure TDetalleRepository.Save(const detalle:TDetalle);
  2. var
  3. RecIndex: Integer;
  4. begin
  5. if FindDetalle(Detalle, RecIndex) then
  6. begin
  7. DataSet.RecNo := RecIndex;
  8. DataSet.Edit;
  9. end
  10. else
  11. DataSet.Append;
  12. DataSet.FieldByName('descripcion').AsString:=Detalle.producto.nombre;
  13. DataSet.FieldByName('cantidad').AsFloat := Detalle.Fcantidad;
  14. DataSet.FieldByName('precio').AsFloat := Detalle.Fproducto.Fprecio;
  15. DataSet.FieldByName('subtotal').AsFloat := Detalle.Fsubtotal;
  16. DataSet.FieldByName('Porc.IVA').AsFloat := Detalle.producto.iva;
  17. DataSet.FieldByName('subtotal2').AsFloat := Detalle.total;
  18. DataSet.FieldByName('AlicuotaIVA').AsFloat := Detalle.FbaseImp;
  19. DataSet.FieldByName('idproducto').AsInteger := Detalle.Fproducto.Fidproducto;
  20.  
  21.  
  22. DataSet.Post;

pero no se porque el string no lo carga, ya comprobe con f9 y llega, tambien con showmessage..

 

Edito:ya lo solucione


  • 0