E' molto comodo poter disporre nel caso di una relazione 1:N della possibilità di creare la relazione "al volo" semplicemente impostando il valore di un attributo della scheda (dal lato N ovviamente).
Sebbene in CMDBuild vi siano i dominii 1:1, non è possibile creare degli attributi con le medesime caratteristiche di praticità.
Per ovviare a questa "mancanza", in seguito a diverse richieste da parte dei miei utenti, ho creato la seguente logica che ad una prima analisi sempra fornire il risultato sperato.
Al momento la stiamo ancora testando quindi usatela in un contesto di produzione a vostro rischio e pericolo...
Ecco gli script da lanciare sul vostro database:
-- Creazione del dominio sulla stessa classe
select * from cm_create_domain('ClasseSelf','CARDIN: 1:1|CLASS1: Classe|CLASS2: Classe|DESCRDIR: connesso a|DESCRINV: connesso aLABEL: Connessione diretta tra oggetti della classe|MASTERDETAIL: false|MODE: reserved|OPENEDROWS: 0|STATUS: active|TYPE: domain') as result
-- Creazione dell'attributo ricorsivo (da GUI non si può creare!)
select * from cm_create_attribute('"Classe"'::regclass,'Self','int4',NULL,FALSE,FALSE,'BASEDSP: false|CLASSORDER: 0|DESCR: oggetto collegato|FIELDMODE: write|GROUP: |INDEX: 1|MODE: write|REFERENCEDIRECT: false|REFERENCEDOM: ClasseSelf|REFERENCETYPE: restrict|STATUS: active') as result;
-- Creazione dell'attributo di conteggio ricorsione
select * from cm_create_attribute('"Classe"'::regclass,'RecSeq','int4',NULL,FALSE,FALSE,'BASEDSP: false|CLASSORDER: 0|DESCR: RecSeq|FIELDMODE: hidden|GROUP: |INDEX: 2|MODE: write|STATUS: active') as result;
-- Imposta il default per i nuovi item che verranno creati
ALTER TABLE "Classe" ALTER COLUMN "RecSeq" SET DEFAULT 0;
-- *** Disabilita i trigger
-- Bonifica valori pre-esistenti
UPDATE "Classe" SET "RecSeq"=0 WHERE "Status"='A';
-- *** Riabilita i trigger
-- Creazione dei trigger per la gestione logica
CREATE OR REPLACE FUNCTION set_data_classe()
RETURNS trigger AS
$BODY$
BEGIN
IF (NEW."RecSeq" <> OLD."RecSeq") THEN
RETURN NEW;
END IF;
IF (NEW."Self" IS NULL) THEN
-- Cancellazione
UPDATE "Classe"
SET "Self"=NULL,"RecSeq"=coalesce("RecSeq",0)+1
WHERE "Status"='A' AND "Id"=OLD."Self";
IF ((SELECT "Id" FROM "Map_ClasseSelf" WHERE ("IdObj1"=NEW."Id" OR "IdObj2"=NEW."Id") AND "Status"='A')IS NOT NULL) THEN
UPDATE "Map_SwitchRouterPortSelf" SET "Status" = 'N' WHERE ("Map_ClasseSelf"."Id" = (SELECT "Id" FROM "Map_ClasseSelf" WHERE ("IdObj1"=NEW."Id" OR "IdObj2"=NEW."Id") AND "Status"='A'));
END IF;
ELSE
-- Update/Inserimento
UPDATE "Classe"
SET "Self"=NEW."Id", "RecSeq"=coalesce("RecSeq",0)+1
WHERE "Status"='A' AND "Id"=NEW."Self";
IF ((SELECT "Id" FROM "Map_ClasseSelf" WHERE ("IdObj1"=NEW."Id" OR "IdObj2"=NEW."Id") AND "Status"='A')IS NULL) THEN
INSERT INTO "Map_ClasseSelf" ("IdClass2","IdClass1","IdObj2","IdDomain","IdObj1","User") VALUES ('"Classe"'::regclass,'"Classe"'::regclass,NEW."Self",'"Map_ClasseSelf"'::regclass,NEW."Id",'admin');
END IF;
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION set_data_Classe() OWNER TO utente;
CREATE TRIGGER set_data_classe
AFTER INSERT OR UPDATE
ON "Classe"
FOR EACH ROW
EXECUTE PROCEDURE set_data_classe();
CREATE OR REPLACE FUNCTION set_data_classeself()
RETURNS trigger AS
$BODY$
BEGIN
IF NEW."Status"='N' THEN
-- Cancellazione
UPDATE "Classe"
SET "Self"=NULL,"RecSeq"=coalesce("RecSeq",0)+1
WHERE "Status"='A' AND "Id"=NEW."IdObj1";
UPDATE "Classe"
SET "Self"=NULL,"RecSeq"=coalesce("RecSeq",0)+1
WHERE "Status"='A' AND "Id"=NEW."IdObj2";
ELSE
-- Creazione
UPDATE "Classe"
SET "Self"=NEW."IdObj1","RecSeq"=coalesce("RecSeq",0)+1
WHERE "Status"='A' AND "Id"=NEW."IdObj2";
UPDATE "Classe"
SET "Self"=NEW."IdObj2","RecSeq"=coalesce("RecSeq",0)+1
WHERE "Status"='A' AND "Id"=NEW."IdObj1";
END IF;
RETURN NEW;
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
ALTER FUNCTION set_data_classeself() OWNER TO utente;
CREATE TRIGGER set_data_classeself
BEFORE INSERT OR UPDATE
ON "Map_ClasseSelf"
FOR EACH ROW
EXECUTE PROCEDURE set_data_classeself();