 |
Club Builder Foro de C++Builder en español
|
| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Jue 18 Oct, 2007 12:15 pm Asunto: Campos autoincrementales: Más dudas en Firebird |
|
|
He estado pensando en algunas de las cosas que me habéis sugerido en otros hilos y he llegado a la conclusión que, efectivamente, me interesa un campo de tipo autoincremental. Ahora bien: por más que he mirado no he logrado descubrir como se hace para definir ese tipo de campos. Con IBManager, al definirlo como tal, crea un trigger y un generador:
| Código: | CREATE TABLE PRUEBA (ID SMALLINT);
SET TERM ^ ;
CREATE TRIGGER BI_PRUEBA_ID FOR PRUEBA ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(PRUEBA_ID_GEN, 1);
END^
SET TERM ; ^ |
Esta estructura, ¿Puede incluirse en un IBSql? _________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
Cesar C. Salazar Gonzalez Master


Registrado: 01 Oct 2002Mensajes: 2155Ubicación: San Cristóbal de Las Casas, Chiapas
|
Publicado: Jue 18 Oct, 2007 9:29 pm Asunto: |
|
|
Hola Angel. como siempre aqui va un pequeño enlace sobre los campos incrementales o Id, en teoria, puedes usar los Triggers, pero si aun no te acostumbras a ellos por la dificultad que se tienen que programar dentro de la base de datos. pues ahi es donde se ejecutan puedes ayudarte de un procedimiento de este enlace
al final de este post, vienen imagenes, que te pueden ayudar a comprender mejor el manejo de los campos autoincrementales
si estas usando alguna version del EMS 2005 hacia arriba, siempre te va a generar el "Trigger" pero puedes eliminarlo en la parte de la izquierda sin ningun problema y usar el "Store Procedure" que es el que trata el ejemplo del post que te envio.
Saludos!! _________________
 |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Vie 19 Oct, 2007 11:21 am Asunto: |
|
|
Gracias por la ayuda César. Después de leer todo me surgen varias dudas:
1ª. Hablas de CREATE GENERATOR. Es instrucción ¿Dónde se ejecuta? ¿Dentro del propio CREATE TABLE? ¿Sólo se ejecuta al crear las tablas?
2ª. El disparador, ¿se ejecuta de forma automática al hacer un INSERT en la tabla o hay que forzar su ejecución? _________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
Cesar C. Salazar Gonzalez Master


Registrado: 01 Oct 2002Mensajes: 2155Ubicación: San Cristóbal de Las Casas, Chiapas
|
Publicado: Vie 19 Oct, 2007 8:23 pm Asunto: |
|
|
Hola Angel Respondiendo a tus preguntas.
| Angel escribió: | | 1ª. Hablas de CREATE GENERATOR. Es instrucción ¿Dónde se ejecuta? ¿Dentro del propio CREATE TABLE? ¿Sólo se ejecuta al crear las tablas? |
la Sentencia "Create Generator" es una sentencia que usa Firebrid y mas concretamente en el lenguaje SQL de Firebird, sirve para declarar una "variable" llamemosle asi, que contiene un valor entero, esta variable es la que se usa para incrementar su valor, que a su vez este valor nos sirve en el campo que hemos declarado en nuestra tabla como ID
por ejemplo, tienes una tabla sencilla de empleados, y cada empleado contienen un valor unico (id)
| Cita: | Empleados:
-------------
id integer not null,
nombre varchar(40),
{... los demas camos...} |
ahora como le ponemos el valor del ID bien como esto no es access y se supone que nosotros controlamos el servidor de Firebird desde programación, debemos crear una "variable" que se auto incremente cada vez que nosotros lo necesitemos.
para ello usas la sentencia "create generator"
| Código: | Create Generator para_campo_id_empleado |
puse el nombre de la variable a "para_campo_id_empleado" pero tu puedes poner el nombre que identifique al campo que te va a servir.
ahora esta variable se incrementa con el uso de la función de SQL "Gen_id", y que dentro de un procedimiento tal y como dice el enlace antes mencionado te regresa el valor.
| Angel escribió: | | 2ª. El disparador, ¿se ejecuta de forma automática al hacer un INSERT en la tabla o hay que forzar su ejecución? |
Cuando los pones dentro de la tabla y activas las sentencias de Insert, Update, Modify y Delete, automaticamente se ejecuta, yo de manera personal no los uso para crear los campos ID, pero si los uso, para enviar eventos a las estaciones cuando se ejecuta un movimiento del cual las otras estaciones deben estar enteradas, esto funciona, asi. dentro de tu modulo de datos introduces un componente IBEvents que es el que se encarga de recibir los Eventos generados por el servidor (puerto RemoteAuxport), cuando alguien modifica por decir el campo cantidad de un producto y se requiere que este sea notificado a las demas estaciones genero el siguiente triguer que se activa cuando se: Inserta, modifica, o borra un producto, el trigger que uso es el siguiente trigger
Donde puedes observar que la "Action" es despues, que la tabla es para productos y que el evento se genera cuando se Update (Actualiza), a parte dentro del cuerpo del Trigger existe una funcion de SQL de firebird que se llama Pos_Event('nombre del evento')
y cada vez que el servidor de Firebrid me envia este evento o cualquier otro, en mi programa donde esta mi modulo de datos y donde tengo el Componente IBEvents y en la parte del Evento OnEvenAlert: (uff me canse de poner "y", jeje)
uso el siguiente codigo
| Código: | void __fastcall TModuloDatos::EV_EventsEventAlert(TObject *Sender,
AnsiString EventName, int EventCount, bool &CancelAlerts)
{
// Evento para Productos
if(EventName=="ccsgProductos")
{
this->Productos->ApplyUpdates();
this->Productos->Transaction->CommitRetaining();
}
// Evento para Productos Imagenes
if(EventName=="ccsgPROD_IMG")
{
this->Productos_IMG->ApplyUpdates();
this->Productos_IMG->Transaction->CommitRetaining();
} |
Asegurandome entonces que con este envento, TODAS las estaciones que lo escuchen automaticamente van actualizar su informacion. algo asi como el refresh() de las tablas de paradox, pero para Firebird y a parte de esto es que no consume recursos.
aun que en la imagen solo aparece marcada la opcion UpDate del trigger, el contenido programatico es de las siguiente manera
| Código: | CREATE TRIGGER PRODUCTOS_AI FOR PRODUCTOS ACTIVE
AFTER INSERT OR UPDATE OR DELETE POSITION 0
AS
BEGIN
POST_EVENT 'ccsgProductos';
END |
Donde dice que se genere "Despues de Insertar o Actualizar o Borrar"
Saludos. _________________
 |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Lun 22 Oct, 2007 1:11 pm Asunto: |
|
|
Gracias César por los mensajes, pero sigo con un problema: No entiendo como funciona este tipo de campos; ni con triggers ni de otra forma. Lo siento, es demasiado complejo, o me lo parece.
Voy a explicar como lo hago ahora a ver si me ilumináis un poco Cuando doy de alta un registro nuevo hago lo siguiente en el OnClick del botón donde pido la inserción:
| Código: | void __fastcall TfPersona::AgregarClick(TObject *Sender)
{
fTablas->qMaxRec->Close();
fTablas->qMaxRec->UnPrepare();
fTablas->qMaxRec->SQL->Text = "SELECT MAX(Registro) Ultimo FROM 'Persona.db'";
fTablas->qMaxRec->Prepare();
fTablas->qMaxRec->Open();
fTablas->Persona->Append();
fTablas->Persona->FieldValues["Registro"] = 1 + fTablas->qMaxRec->FieldByName("Ultimo")->AsInteger;
DBEdit1->SetFocus();
} |
El problema viene porque al estar instalada en red la aplicación, ya me ha ocurrido que dos personas han ejecutado a la vez el comando Alta y han aparecido dos registros con el mismo número. Como el índice no es sólo sobre el número de registro no hay error en la inserción. _________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
Cesar C. Salazar Gonzalez Master


Registrado: 01 Oct 2002Mensajes: 2155Ubicación: San Cristóbal de Las Casas, Chiapas
|
Publicado: Lun 22 Oct, 2007 2:18 pm Asunto: |
|
|
Bien intentare ser lo mas espesificio posible, aun que no es mucho lo que voy a generar, mas bien una manera de usar los campos autoincrementales.
Usando tu mismo ejemplo nada mas que haciendo algunas modificaciones al codigo. supongamos que tienes un formulario ABC - ( Altas, Bajas, Cambios) estos formularios que siempre viene a compañados de los clasicos botones GC ( Grabar, Cancelar), aun que puede variar un poco de lo que tienes, pero igual es funcionabe, pues nos ayudamos de Interbase / Firebird, declaramos una varible booleana que es la que nos va a servir para dicho caso.
| Código: | archivo.h
-----------
public: // User declarations
bool Registro_Nuevo; |
En tu Boton Agregar a mi jucio personal solo debe existir la sentcia, Insert() de tu tabla o IBDataSet.
| Código: | void __fastcall TfPersona::AgregarClick(TObject *Sender)
{
this->Registro_Nuevo = true; // indicamos que es nuevo
fTablas->Persona->Insert();
DBEdit1->SetFocus();
} |
lo que estamos diciendo a firebird es que se generé un espacio dentro de la tabla y nos vamos al primer DBEdit que tiene para insertar o modificar
y dentro del boton Guardar de nuestro formulario hacemos algo como esto
| Código: | void __fastcall TfPersona::tbGrabarClick(TObject *Sender)
{
if(this->Registro_Nuevo)
{
// generacion de ID
fTablas->spPersona->ExecProc();
fTablas->Persona->FieldValues["Registro"] = fTablas->Persona->spPersona->ParamByName("new_value")->Value;
}
fTablas->spPersona->Post();
fTablas->spPersona->ApplyUpdates();
fTablas->spPersona->Transaction->CommitRetaining();
} |
el paramatro "new_value" esta declarado en el procedimiento (mas abajo), asi solo cuando el registro sea nuevo, se genera un ID para ese registro
y cuando sea una edicion solo se graban las mofidificaciones.
para no confundir, tambien te paso el boton Editar
| Código: | void __fastcall TfPersona::EditarClick(TObject *Sender)
{
this->Registro_Nuevo = false; // indicamos que NO es nuevo
fTablas->Persona->Edit();
DBEdit1->SetFocus();
} |
Bien antes que nada vamos a usar nuestro servidor de datos para poder trabajar con el Generator.
1.- Abre el programa que te sirve para administrar las bases de datos e intenta crear un generator de nombre ID_PERSONA
| Código: | CREATE GENERATOR "id_persona" |
2.- con el mismo programa que usas ahora intenta crear un procedimiento llamado Gen_Personas,
| Código: | CREATE PROCEDURE GEN_Personas
RETURNS (NEW_VALUE INTEGER)
AS
BEGIN
NEW_VALUE = GEN_ID(ID_persona, 1);
END |
Este procedimiento es el que nos va a servir para incrementar el generador de registros.
(tanto los prefijos ID y los prefijos GEN que uso es para no confundirme asi, se que son ID generadores y GEN son los procedimientos.)
3.- Regresamos a C++ Builder y dentro de tu Modulo de Datos el cual considero se encuentra de esta manera con componentes IBDataSet y DataSource, por cada par de estos componentes agregamos un nuevo componente llamado TIBStoreProc. donde en este ultimo modificamos sus propiedades de la siguiente manera
| Código: | TIBStoredProc:
------------------
DataBase : <Tu base de datos>
StoredProcName : <Nombre del prociedimento almacenado en este caso es GEN_Personas >
Name : <Le pondremos spPersona> |
y asi ya podremos usarlo en nuestra aplicación con el codigo anterior del boton grabar, se que puede ser algo tedioso el recomponer tu aplicacion, pero es preferible hacerlo antes que cuando el sistema tenga mas complejidad.
Saludos y estamos en contacto. _________________
 |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Mar 23 Oct, 2007 10:14 am Asunto: |
|
|
Muchísimas gracias César. Ahora me ha quedado mucho más claro. Sólo una pregunta: Dado que la base de datos (tablas, vistas, la propia base de datos, etc.) se crea en tiempo de ejecución si no existe, los CREATE GENERATOR, CRATE PROCEDURE ¿pueden crearse de forma dinámica?
Otra cosa que viene: todo lo que has incluido en el evento tbGrabarClick, ¿ no sría más lógico que estuviera en el BeforeInsert de la tabla? _________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
Cesar C. Salazar Gonzalez Master


Registrado: 01 Oct 2002Mensajes: 2155Ubicación: San Cristóbal de Las Casas, Chiapas
|
Publicado: Mar 23 Oct, 2007 6:40 pm Asunto: |
|
|
| Angel escribió: | | Dado que la base de datos (tablas, vistas, la propia base de datos, etc.) se crea en tiempo de ejecución si no existe, los CREATE GENERATOR, CRATE PROCEDURE ¿pueden crearse de forma dinámica? |
Si, todos estos pasos pueden hacerse de forma dinámica sin ningún problema.
| Angel escribió: | | todo lo que has incluido en el evento tbGrabarClick, ¿ no sría más lógico que estuviera en el BeforeInsert de la tabla? |
si, pero si piensas usar los Triggers para enviar mensajes estos se van activar antes de que grabes y puede causarte un conflicto con las estaciones, a parte de esta manera evito el error humano que se grabe antes y luego se arrepienta, indicando asi, que el ultimo dato que se grabe, me activará el generador correspondiente, esto implica que la ultima persona que llegue y genere un registro nuevo el campo autoincrementable se activará correctamente.
Saludos!! _________________
 |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Mie 24 Oct, 2007 8:37 am Asunto: |
|
|
Gracias César.
| César C. Salazar González escribió: | | de esta manera evito el error humano que se grabe antes y luego se arrepienta, indicando asi, que el ultimo dato que se grabe, me activará el generador correspondiente, esto implica que la ultima persona que llegue y genere un registro nuevo el campo autoincrementable se activará correctamente. |
¡Hombre! Puse BeforInsert proque fue el primero que me vino a la cabeza; viendo luego los eventos de las tablas puede elegirse BeforePost, por ejemplo.
A lo mejor estoy equivocado, pero poniendo el cálculo como tú en el ejemplo en AgregarClick ¿no se corre el riesgo de que desde dos estaciones se pulse a la vez ese botón? Entonces tendrían ambos registros el mismo valor.
| César C. Salazar González escribió: | | si piensas usar los Triggers para enviar mensajes |
A la vista de lo que me has comentado, creo que será mejor no usar triggers, creo yo. _________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
Cesar C. Salazar Gonzalez Master


Registrado: 01 Oct 2002Mensajes: 2155Ubicación: San Cristóbal de Las Casas, Chiapas
|
Publicado: Mie 24 Oct, 2007 9:03 am Asunto: |
|
|
| Angel escribió: | | A lo mejor estoy equivocado, pero poniendo el cálculo como tú en el ejemplo en AgregarClick ¿no se corre el riesgo de que desde dos estaciones se pulse a la vez ese botón? Entonces tendrían ambos registros el mismo valor. |
No, por que los dos usuarios aun que pulsen el boton AgregarClick, esten generando un "nuevo" registro en la base, este NO se grabará hasta que pulsen el boton Guardar, del ejemplo que te mencióno, pues los dos usuarios puden perder tiempo copiando o estableciendo la información, y cuando pulsen el boton "Guardar" en la forma que estoy tratando, el primero que pulse es el primero que modifica el valor del generador, si el segundo lo pulsa entonces activará el generador ya con el valor correcto, este registro NO se graba hasta que apliquen el ApplyUpdate y Activen la Transacción para guardar hasta ese momento, el registro NO se graba, si usas Before, este sucede antes, y eso no es lo que se desea, si no que se desea hasta que confirmen la transaccion dentro del boton Grabar.
| Angel escribió: | | A la vista de lo que me has comentado, creo que será mejor no usar triggers, creo yo. |
En este caso y en este método, no es conveniente, aun que pueden darte mas soluciones, los demas del foro, pues esta es una solucion, que a mi en lo particular me funciona y conectando las bases de datos hasta en internet, recuerda el ultimo que grabe, es el ultimo que modifica el valor, no se hace antes ni se hace despues. puedes poner un for de 1 a 100 con la sentencia Insert(), pero hasta que no se apliquen las "ApplyUpdate" y el "Transacction->CommitRetaining()" estos 100 registros no se van a grabar.
Saludos!! _________________
 |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Mie 24 Oct, 2007 10:02 am Asunto: |
|
|
De acuerdo. Como ves, sigo teniendo muchas carencias en lo que se refiere al manejo de bases de datos. Otra cosa: el código
| Código: | CREATE PROCEDURE GEN_Personas
RETURNS (NEW_VALUE INTEGER)
AS
BEGIN
NEW_VALUE = GEN_ID(ID_persona, 1);
END |
¿Cómo se pondría para ejecutarlo dinámicamente? ¿Valdría algo así?
| Código: | IBSql->SQL->Add("CREATE PROCEDURE 'Gen_personas'");
IBSql->SQL->Add("RETURNS (NEW_VALUE INTEGER)");
IBSql->SQL->Add("AS");
IBSql->SQL->Add("BEGIN");
IBSql->SQL->Add("NEW_VALUE = GEN_ID(ID_persona, 1);");
IBSql->SQL->Add("END"); |
_________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
Cesar C. Salazar Gonzalez Master


Registrado: 01 Oct 2002Mensajes: 2155Ubicación: San Cristóbal de Las Casas, Chiapas
|
Publicado: Mie 24 Oct, 2007 10:06 am Asunto: |
|
|
La opcion que me comentas, al agregarlo a una consulta es para "crear" el procedimiento, se asume que este codigo, YA esta echo en tu servidor.
pero con lo que me estas estableciendo, es solo para Crearlo, para ejecutarlo ayudate de los IBStoredProcedure como te comento en los post anteriores.
Saludos. _________________
 |
|
| Volver arriba |
|
 |
Angel Master


Registrado: 15 Abr 2003Mensajes: 2311Ubicación: Toledo (España)
|
Publicado: Mie 24 Oct, 2007 10:38 am Asunto: |
|
|
El tema de la ejecución me ha quedado, creo, claro. Yo te preguntaba por como ejecutar el CREATE PROCEDURE de forma dinámica. Es decir: Los dos creates que indicas, ¿pueden incluirse en sendos IBSql? ¿Podría hacerse esto?
| Código: | IBSql->Close();
IBSql->SQL->Text = "CREATE GENERATOR 'Id_personas'";
IBSql->Prepare();
IBSql->ExecQuery();
IBSql->Close();
IBSql->SQL->Clear();
IBSql->SQL->Add("CREATE PROCEDURE 'Gen_personas'");
IBSql->SQL->Add("RETURNS (NEW_VALUE INTEGER)");
IBSql->SQL->Add("AS");
IBSql->SQL->Add("BEGIN NEW_VALUE = GEN_ID(ID_persona, 1);");
IBSql->SQL->Add("END");
IBSql->Prepare();
IBSql->ExecQuery();
|
Si no, ¿cómo habría de ponerse el código? Perdona que te esté dando tanto al lata con esto. _________________ Un saludo
Necesitamos tu ayuda: Envía AI al 27595 (Coste 1,20 euros + IVA) |
|
| Volver arriba |
|
 |
Cesar C. Salazar Gonzalez Master


Registrado: 01 Oct 2002Mensajes: 2155Ubicación: San Cristóbal de Las Casas, Chiapas
|
Publicado: Mie 24 Oct, 2007 10:46 am Asunto: |
|
|
Efectivamente asi es, como estas son sentencias que ocupa el mismo Firebird, no existe ningun problema al ejecutarlos. ahora bien como siempre, cuando las ejectues por segunda vez, salta la excepcion pues ya estan creadas.
Asi de sencillo como lo has puesto, se crean dentro del servidor, y usando la misma manera que estas usando puedes crear todas las sentencias que requeras en tu base de datos.
Saludos. _________________
 |
|
| Volver arriba |
|
 |
alfredo Master

Registrado: 13 Oct 2003Mensajes: 246Ubicación: Valencia Venezuela
|
Publicado: Mie 31 Oct, 2007 9:58 pm Asunto: |
|
|
Hola saludos Cesar Y Angel, he estado leyendo los post y creo que Angel esta teniendo el mismo problema que tuve cuando empece a usar servidores de datos serios.
Angel vienes con los esquemas de quienes trabajamos con clipper y luego con paradox etc. Una gran diferencia entre un servidor de datos activo y una base de datos "plana" es que el servidor maneja eventos y se le puede meter codigo a la base de datos. Lo bueno de esto es que por un lado se simplifica el desarrollo del lado cliente (tu programa) y se garantiza la consistencia y logica de los datos (reglas de empresa).
Con clipper nos acostumbramos a manejar absolutamente todo desde nuestras aplicaciones, insertamos un registro de factura, le asignamos su correlativo, apuntamos en el libro de ventas y si es a credito en cuentas por cobrar, rebajamos el inventario etc. etc...
Con Firebird podemos crear una base de datos que cuando se inserte una factura esta se numere automaticamente, escriba al libro de ventas etc. etc.... independientemente de la aplicacion que la accese.
Una vez creada la base de datos que "trabaja sola" crear la aplicacion es coser y cantar.
Autonumericos, estos no existen en firebird, puedes simularlos mediante un trigger Before Update usando o no un generator.
Los triggers son respuestas a eventos basicos en el manejo de registros, puede resultar confuso el After Insert y el Before Insert pero hay una regla simple:
Si se modifica el propio registro ej. poner su correlativo Before Insert.
Cuando hay que crear o modificar registros en otras tablas After Insert.
Lo mismo aplica para las acciones Update y Delete de hecho con este ultimo puedes guardar los datos en una tabla papelera con Before Delete,
cuando se borre un registro, con After Delete ya no es posible pues ahi el registro ya ha sido borrado.
Ojo, me refiero a los eventos en el servidor no a los de las tablas de la VCL.
Los generadores en firebird son contadores dentro de la propia BD, cuando se pide el siguente mediante la funcion GEN_ID el contador se incrementa, no hay forma de devolver el numero pedido sin exponerse a desastres, es como sacar un ticket de turno en un banco, si por alguna causa no se concreta la transaccion el generador continua incrementado.
Esto no es bueno para los correlativos de facturas pues podrian saltarse numeros y esto no les hace mucha gracia a los contadores.
Para generar numeros consecutivos y no repetidos puedes usar el siguente trigger:
| Código: | create trigger correlativo for facturas active before insert
as
declare variable numero integer;
begin
select max(numero) from facturas into numero;
if(numero is null) then numero=1;/*caso primera factura*/
else new.numero=numero+1;
end
|
El uso de procedimientos almacenados desde la aplicacion es util pero en algunos casos no recomendable, traerse por ejemplo el correlativo con un procedure al insertar y usar este para establecer la relacion master/detail con la tabla de detalles puede parecer una buena idea pero hay que tener en cuenta que firebird utiliza el sistema de universos paralelos para controlar la concurrencia y en otros universos pueden haberse insertado algunas facturas y de alguna manera abortarse este quedando asi un hueco en la numeracion.
Para el enlace master/detail utilizo un indice artificial el cual traigo con un procedure, la numeracion se la dejo al trigger pues esta se activa en el servidor al realizar el commit y este esta viendo las otras transacciones concurrentes y las aplica una por una por lo cual no puede haber error de numeracion.
Para mis aplicaciones primero creo la BD usando IBConsole y le meto todo el codigo relativo a las reglas de empresa luego hago la interfaz en cualquier lenguaje que maneje conexion con firebird esto me permite acceder desde windows, linux o web con la seguridad que todo funcionara bien.
Espero haber sido de ayuda. |
|
| Volver arriba |
|
 |
|
|
No puedes publicar temas nuevos en este foro No puedes responder a temas en este foro No puedes editar tus mensajes en este foro No puedes borrar tus mensajes en este foro No puedes votar en las encuestas de este foro
|
© 2002–2026 Club Builder · Funciona con phpBB.
|