Vous n'êtes pas identifié(e).

#1 22/05/2012 11:17:09

Gold.Strike
Membre

Triggers sur des tables liées

Bonjour,

Nous utilisons des triggers sur notre base de données, afin d'alimenter une table "synchronisation" permettant de synchroniser les données d'une base cliente à partir d'une base serveur. Seule une partie des tables de la base sont synchronisées. La liste des tables synchronisées est définie dans une table de la base : "synchro_entite".

Parmis les tables synchronisées, il y en a 3 qui sont liées à une GED, et qui permettent de récupérer des images ou documents, liés à d'autres tables de la BDD. Ces 3 tables sont :
- "document" : qui contient le nom du document, et le type du document
- "doclien" : qui fait la relation entre un document et une entité de la base (le nom de la table + son id)
- "docversion" : qui contient des infos sur le document (date, utilisateur, taille,...) et le OID lié au document

Lors de l'ajout d'un document, on insère bien des données dans les 3 tables successivement. Mais il est possible qu'une insertion se passe mal, et que seule la table "document" soit mise à jour.
De même, on sait si le document est à synchronisé que lorsqu'on mets à jour "doclien", car c'est lui qui sait à quelle table est liée un document.

Le trigger actuellement utilisé est le suivant :

-- Function: fct_add_document_to_synchro()
-- DROP FUNCTION fct_add_document_to_synchro();
CREATE OR REPLACE FUNCTION fct_add_document_to_synchro()
  RETURNS trigger AS
$BODY$

DECLARE
	curtime timestamp;
	ptrs_id bigint;
	type_op text;	
	table_name text;
	i_count integer;
	i_synchro integer;

BEGIN 
	type_op := TG_OP;
	IF type_op LIKE 'DELETE' THEN
		return OLD;
	END IF;

	curtime := 'now';
	ptrs_id := NEW.id;
	table_name := TG_TABLE_NAME;
	i_synchro := 1;

	-- si table 'document' et opération 'update' 
	IF table_name = 'document' AND type_op LIKE 'UPDATE' THEN
		-- i_synchro = nb d'occurences dans 'doclien' liés au document_id (ptrs_id) et 
		SELECT INTO i_synchro COUNT(1) FROM doclien dl 
		WHERE document_id = ptrs_id
		AND UPPER(dl.entite) IN (
			SELECT UPPER(nomtable) FROM synchro_entite WHERE actif = true
		);

	-- si table 'doclien' 
	ELSIF table_name = 'doclien' THEN
		SELECT INTO i_synchro COUNT(1) FROM synchro_entite s_e 
		WHERE UPPER(s_e.nomtable) = UPPER(NEW.entite)
		AND s_e.actif = true;

	-- si table 'docversion' 
	ELSIF table_name = 'docversion' THEN
		SELECT INTO i_synchro COUNT(1) FROM doclien dl 
		WHERE document_id = NEW.document_id
		AND	UPPER(dl.entite) IN (
			SELECT UPPER(nomtable) FROM synchro_entite WHERE actif = true
		);

	-- sinon
	ELSE 
		i_synchro = 0;
	END IF;


	IF i_synchro > 0 THEN
		 -- Verifie s'il n'existe pas déja un enregistrement dans la base
		 SELECT INTO i_count COUNT(nom_table) FROM synchronisation 
		 WHERE id_ptrs = ptrs_id AND nom_table = table_name ;

		 IF i_count <= 0 THEN
			 INSERT INTO synchronisation (id_ptrs, nom_table, etat, date_maj_ptrs)
			 VALUES (ptrs_id, table_name, type_op, curtime);
		 ELSE
			UPDATE synchronisation 
				SET etat = type_op, date_maj_ptrs = curtime
			WHERE id_ptrs = ptrs_id AND nom_table = table_name;
		 END IF;
	 END IF;

	RETURN NEW;

END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100;
ALTER FUNCTION fct_add_document_to_synchro() OWNER TO postgres;
GRANT EXECUTE ON FUNCTION fct_add_document_to_synchro() TO public;
GRANT EXECUTE ON FUNCTION fct_add_document_to_synchro() TO postgres;
COMMENT ON FUNCTION fct_add_document_to_synchro() IS 'Fonction d''ajout d''enregistrements de documents dans la table ''synchronisation'' (serveur/PTRS)';

Il ne me convient pas, car il ne marche que pour un UPDATE. Il faudrait que je l'adapte pour qu'il marche aussi dans le cas ou on ajoute un document. Mais comme le document est ajouté avant doclien, je ne sais pas trop quelle solution utiliser :
- faire un update de "document" après avoir inséré un "doclien" dans ma méthode de sauvegarde, pour que le trigger soit appelé?
- ajouter systématiquement tous les documents ajoutés via le trigger, et créer un trigger qui va "faire le ménage" après avoir ajouté un "doclien"?

Hors ligne

#2 22/05/2012 14:32:05

edlm
Membre

Re : Triggers sur des tables liées

Gold.Strike a écrit :

De même, on sait si le document est à synchronisé que lorsqu'on mets à jour "doclien", car c'est lui qui sait à quelle table est liée un document.

donc le trigger est actuellement posé sur la table doclien ?


Gold.Strike a écrit :

Il ne me convient pas, car il ne marche que pour un UPDATE. Il faudrait que je l'adapte pour qu'il marche aussi dans le cas ou on ajoute un document. Mais comme le document est ajouté avant doclien, je ne sais pas trop quelle solution utiliser :

je suis désolé mais ce que vous décrivez m'apparaît confus (ca vient probablement de moi ;-)).


Pouvez vous préciser à partir de quel(s) succession d'événement(s) une synchronisation doit elle être planifiée ?
Dès l'insertion/modification de documents ou seulement après que doclien ait été mis à jour ?
Ou une autre succession de mises à jour, peu importe mais merci de la définir précisément ?


Si il s'agit "simplement" de synchroniser chaque table indépendamment de ce qui se passe dans les autres je suppose qu'une solution envisageable
est de poser la même fonction triggers sur toutes les tables qui se contenterait d'enregistrer dans la table synchronisation les modifications
effectuées.


Par contre si la synchronisation ne doit intervenir que sous certaines conditions qui concernent de multiples tables la solution sera différente.


Éric

Hors ligne

#3 22/05/2012 15:15:34

Gold.Strike
Membre

Re : Triggers sur des tables liées

C'est vrai que j'ai oublié de préciser que nous avions un déclencheur pour chacune de ces 3 tables. Par exemple, pour la table "document", le trigger est :

-- Trigger: TRG_AFTER_DOCUMENT on "document"
-- DROP TRIGGER "TRG_AFTER_DOCUMENT" ON "document";
CREATE TRIGGER "TRG_AFTER_DOCUMENT"
  AFTER INSERT OR UPDATE OR DELETE
  ON "document"
  FOR EACH ROW
  EXECUTE PROCEDURE fct_add_document_to_synchro();

Et c'est donc ce déclencheur qui appelle la fonction trigger que j'ai présenté dans mon premier message : "fct_add_document_to_synchro".

La synchronisation sera planifiée chaque jour pour mettre à jour les données du client à partir de nos données.
Les triggers servent donc à alimenter la table "synchronisation" qui sera utilisée lors de la synchronisation.

Hors ligne

#4 22/05/2012 15:58:20

Marc Cousin
Membre

Re : Triggers sur des tables liées

Moi, ce qui m'échappe, c'est ce paragraphe:
«Lors de l'ajout d'un document, on insère bien des données dans les 3 tables successivement. Mais il est possible qu'une insertion se passe mal, et que seule la table "document" soit mise à jour.» Pourquoi ne pas utiliser une transaction ? C'est à ça qu'elles servent, et ça vous simplifierait le problème non ?


Marc.

Hors ligne

#5 22/05/2012 16:43:26

Gold.Strike
Membre

Re : Triggers sur des tables liées

Marc Cousin a écrit :

Moi, ce qui m'échappe, c'est ce paragraphe:
«Lors de l'ajout d'un document, on insère bien des données dans les 3 tables successivement. Mais il est possible qu'une insertion se passe mal, et que seule la table "document" soit mise à jour.» Pourquoi ne pas utiliser une transaction ? C'est à ça qu'elles servent, et ça vous simplifierait le problème non ?

Ca résuoudrait certainement le problème oui.
Mais le prestataire qui avait développé pour nous la solution n'a utilisé nulle part de transactions, de clés étrangères, ou de bonnes pratiques qu'on devrait sans doute retrouver avec une base PostgreSQL...
Du coup, l'idée est surtout de finaliser le module de synchronisation des données le plus simplement possible, sans revenir sur la "pseudo" couche d'accès aux données existantes pour le reste de la solution.

Hors ligne

#6 22/05/2012 16:56:51

Marc Cousin
Membre

Re : Triggers sur des tables liées

Sinon, pour répondre à la question initiale, je pense que la première solution (update) est plus propre et plus sûre que la seconde (ménage).


Marc.

Hors ligne

#7 22/05/2012 17:01:37

Gold.Strike
Membre

Re : Triggers sur des tables liées

D'accord merci.

Hors ligne

Pied de page des forums