Xlookup: Unterschied zwischen den Versionen
(5 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
Zeile 53: | Zeile 53: | ||
progchg varchar2(40) | progchg varchar2(40) | ||
); | ); | ||
+ | |||
+ | Die Tabelle für die Übersetzungen gehört eigentlich in den Namensbereich translate_ und ist hier nur informativ aufgeführt. | ||
==Code== | ==Code== | ||
Zeile 114: | Zeile 116: | ||
Der Ex- und Import der Nachschlagelisten ist ziemliches Standard-Vorgehen. Erwähnenswert mag noch sein, dass die Übersetzungen in xtranslate ex- und importiert werden. | Der Ex- und Import der Nachschlagelisten ist ziemliches Standard-Vorgehen. Erwähnenswert mag noch sein, dass die Übersetzungen in xtranslate ex- und importiert werden. | ||
+ | |||
+ | ===xlookup_flt=== | ||
+ | |||
+ | #tree_clear | ||
+ | |||
+ | ~ $NEMPTY($EDT(edt1)) | ||
+ | #sql select l.* from data_list l | ||
+ | #sql left outer join data_list_item i on l.data_list_id = i.data_list_id | ||
+ | #sql left outer join translate_list_item t on i.data_list_item_id = t.data_list_item_id | ||
+ | #sql where upper(l.name) like upper(:kedt) | ||
+ | #sql or upper(i.cvalue) like upper(:kedt) | ||
+ | #sql or upper(t.cvalue) like upper(:kedt) | ||
+ | #sql order by l.name; | ||
+ | #tree_node u=root t=data_list c1=name s="#page_fill d=xlookup_page_list" o=xlookup_open(list) | ||
+ | #tree_fillsql kedt=$EDT(edt1)% | ||
+ | |||
+ | ~ | ||
+ | #sql select * from data_list order by category, name; | ||
+ | #tree_node u=root k=category c1=category nc=Y s="#page_fill d=xlookup_page_category" | ||
+ | #tree_node u=last t=data_list c1=name s="#page_fill d=xlookup_page_list" o=xlookup_open(list) | ||
+ | #tree_fillsql mex=3 | ||
+ | |||
+ | ~~ | ||
+ | |||
+ | Wenn ein Filter-Begriff in edt1 eingegeben ist, dann wird nach diesem in den Namen der Liste, den Listeneinträgen sowie in den Übersetzungen der Listeneinträge gesucht; letztlich ist das nur ein entsprechendes SQL-Statement, das die Ergebnisse dann im Baum aufführt. | ||
+ | |||
+ | Gibt es keinen Filter-Begriff, werden die Namen aller Listen geladen und diese nach Kategorien gruppiert. Der Baum wird also zunächst in zwei Ebenen gefüllt. Die Listeneinträge werden dann bei Bedarf nachgeladen (o=xlookup_open(list)). Gibt es nicht mehr als drei Kategorien, werden diese gleich geöffnet (mex=3). | ||
+ | |||
+ | ===xlookup_open=== | ||
+ | |||
+ | #sql select data_list_item_id, ckey, cvalue from data_list_item where data_list_id = :kid and status = 1; | ||
+ | #tree_node u=exp t=data_list_item c1=ckey c2=cvalue s="#page_fill d=xlookup_page_item" | ||
+ | #tree_fillsql kid=$FND(o,data_list_id) | ||
+ | |||
+ | In xlookup_open werden die Einträge einer Liste nachgeladen, wenn der entsprechende Eintrag im Baum geöffnet wird. Die Vorgehensweise ist auch hier sehr "Standard". Erwähnenwert vielleicht noch, dass nur aktive Listeneinträge nachgeladen werden. | ||
+ | |||
+ | Ein Hinweis noch zu $FND(o,data_list_id) - hier brauchen wir nicht den selektierten Eintrag im Baum, sondern denjenigen, der gerade geöffnet wird. Datum ist hier als erster Parameter o und nicht s zu verwenden. | ||
+ | |||
+ | ===xlookup_page_category=== | ||
+ | |||
+ | #page n=category | ||
+ | |||
+ | #prim as=Y | ||
+ | #cat as=Y c=$T(Lists_of_the_category) | ||
+ | |||
+ | #grd_seg frc=0 fcc=1 clt=ss mhc=300 n=item | ||
+ | #grd_col c1=ID f=data_list_id w=30 y=guid ro=Y | ||
+ | #grd_col c1=Name f=name w=200 l=40 | ||
+ | #grd_col c1=$T(Description) f=description w=400 wst=500 l=80 r=admin | ||
+ | #sql select * from data_list where category = :k_cat order by name | ||
+ | #grd_data q=sql t=data_list k_cat=$FND(s,category) | ||
+ | |||
+ | Auf dieser Seite werden alle Listen einer Kategorie mit Namen und Beschreibung gelistet (und können dort bearbeitet werden). | ||
+ | |||
+ | Hinweis zur Beschreibung: Hier haben wir eine Rechtesetzung auf die Spalte (r=admin). Das heißt, Benutzer ohne Admin-Rechte können die Beschreibung noch nicht mal lesen, da sie in der Rechtedefinition in xlookup darauf kein Leserecht bekommen haben. | ||
+ | |||
+ | ===xlookup_page_item=== | ||
+ | |||
+ | #page | ||
+ | |||
+ | #prim as=Y | ||
+ | #cat as=Y c=$T(Translation) | ||
+ | |||
+ | #grd_seg frc=0 fcc=1 clt=ss n=grid | ||
+ | #grd_col f=translate_list_item_id c1="ID" w=30 y=guid ro=Y nvi=$GUID() | ||
+ | #grd_col f=data_list_item_id c1="Data List Item Id" w=0 ro=Y | ||
+ | #grd_col f=translate_language_id c1="Translate Language Id" w=0 ro=Y | ||
+ | #grd_col f=name c1=$T(Language) ro=Y nd=Y | ||
+ | #grd_col f=cvalue c1=$T(Translation) w=300 wst=500 | ||
+ | #sql select t.translate_list_item_id, i.data_list_item_id, l.translate_language_id, l.name, t.cvalue | ||
+ | #sql from data_list_item i | ||
+ | #sql inner join translate_language l on 1 = 1 | ||
+ | #sql left outer join translate_list_item t | ||
+ | #sql on i.data_list_item_id = t.data_list_item_id and l.translate_language_id = t.translate_language_id | ||
+ | #sql where i.data_list_item_id = :kid | ||
+ | #grd_data q=sql t=translate_list_item kid=$FND(s,data_list_item_id) | ||
+ | |||
+ | Etwas tricky ist der Code für die Übersetzung der einzelnen Einträge. Die Übersetzungen stehen in der Tabelle translate_list_item, diese benötigt neben der eigenen ID (translate_list_item_id) auf die ID des Listeneintrags (data_list_item_id) und der Sprache (translate_language_id). Die beiden Letztgenannten sind als unsichtbare Spalten (w=0) im Grid angelegt. | ||
+ | |||
+ | Angezeigt dagegen wird der Name der Sprache (f=name), dieser wird jedoch nicht in der Tabelle gespeichert, also muss die Spalte mit nd=Y (NoData) von der Speicherung ausgenommen werden. Da dann eine Änderung auch keinen Sinn ergibt, wird mit ro=Y (ReadOnly) auch die Beschreibbarkeit entfernt. | ||
+ | |||
+ | Das SQL-Statement ist ein Full Join zwischen Listeneinträgen und Sprachen, so dass diese IDs stets vorliegen. | ||
+ | |||
+ | ===xlookup_page_list=== | ||
+ | |||
+ | #page | ||
+ | |||
+ | #prim as=Y | ||
+ | #cat as=Y c=$T(List) | ||
+ | |||
+ | #vl_seg cnt=2 clt=ss w1=100 w2=300 wst2=300 c=" " b=H n=list | ||
+ | #vl_line c1=ID f2=data_list_id ro2=Y nvic2=$GUID() | ||
+ | #vl_line c1=$T(Category) f2=category nvi2=$FND(s,category) l2=40 | ||
+ | #vl_line c1=Name f2=name l2=40 | ||
+ | #vl_line c1=$T(Description) f2=description l2=80 | ||
+ | #vl_data q=t t=data_list kid=$FND(s,data_list_id) | ||
+ | |||
+ | #prim as=Y | ||
+ | #cat as=Y c=$T(Items) | ||
+ | #btns_seg | ||
+ | #btns_btn c="$T(Add item)" w=150 cmd="#grd_add i=item f_status=1" | ||
+ | |||
+ | #grd_seg frc=0 fcc=1 clt=ss mhc=300 n=item c=" " b=H | ||
+ | #grd_col c1=ID f=data_list_item_id w=30 y=guid nvi=$GUID() | ||
+ | #grd_col f=data_list_id w=0 nvic=$PVAL(list,data_list_id) nvic_=$FND(s,data_list_id) | ||
+ | #grd_col c1=$T(Key) f=ckey w=100 l=40 | ||
+ | #grd_col c1=$T(Value) f=cvalue w=200 wst=500 l=80 | ||
+ | #grd_col c1=Sort f=csort y=int l=4 | ||
+ | #grd_col c1=Status f=status w=80 y=lookup ld=general_status | ||
+ | #sql select * from data_list_item where data_list_id = :kid order by csort | ||
+ | #grd_data q=sql t=data_list_item kid=$FND(s,data_list_id) | ||
+ | |||
+ | Auf der Seite der Listen können auch gleich deren Einträge bearbeitet werden. Sofern keine Mehrsprachigkeit gewünscht ist, muss man also nicht "tiefer" in den Baum. | ||
+ | |||
+ | Oben werden Name und Beschreibung der Liste in einem VL-Segment gepflegt. Erwähnenswert vielleicht der Paramter nvic2=$GUID(): Liegt keine ID vor (in diesem Fall soll wohl eine neue Liste erstellt werden), so wird eine neue GUID erzeugt. Gleichzeitig wird der Datensatz als ''inserted'' gekennzeichnet (somit dann ein INSERT- statt einem UPDATE-Statement), und er wird gleich auch ''changed'' gesetzt - damit werden Save- und Cancel-Button verfügbar, so dass die Neuanlage der Liste mit Cancel abgebrochen werden kann. | ||
+ | |||
+ | In dem Grid-Segment werden die einzelnen Einträge bearbeitet. Der Button im darüber liegenden Button-Segment legt einen neuen Datensatz an - da hier nur eine einzelne Prozedur benötigt wird, wird diese gleich in den Parameter cmd geschrieben; damit die Parameter korrekt zugeordnet werden können, sind da allerdings Anführungszeichen erforderlich. Ein neuer Datensatz benötigt nicht nur eine ID, sondern auch eine Referenz auf die Liste. Hier sind parallel zwei Möglichkeiten gezeigt: Die erste funktioniert mit $PVAL und zieht die ID der Liste auf dem VL-Segment. Die zweite Möglichkeit zieht die ID aus dem Baum - das funktioniert auch bei neu angelegten Datensätzen, da die ID schon vor dem Speichern vom VL-Segment in den Baum geschrieben wird. |
Aktuelle Version vom 10. Mai 2021, 19:33 Uhr
Inhaltsverzeichnis
xlookup - Nachschlagelisten
In Datenbankanwendungen werden häufig Auswahllisten verwendet, in denen der Anwender einen Wert aus einer Menge von Optionen auswählen kann. In der Datenbanktabelle werden dann häufig nur Schlüsselwerte gespeichert, während die Anwendung die Option im Klartext anzeigt.
Im BAF-Framework werden solche Nachschlagelisten in xlookup angelegt, gefüllt und übersetzt.
Liste
Eine Nachschlageliste muss zwingend einen Namen haben, über diesen wird sie im Code adressiert. Damit die Übersicht bei einer Vielzahl von Nachschlagelisten nicht verloren geht, werden die in Kategorien gruppiert. Zur weiteren Erläuterung kann eine Beschreibung ergänzt werden.
Im Abschnitt Einträge kann die Liste mit Einträgen gefüllt werden. Neben einem Schlüssel und einem Wert hat ein Eintrag eine Sortierreihenfolge sowie einen Status. Mit dem Status kann der Datensatz auf inaktiv gesetzt werden, er erscheint dann nicht mehr in der Liste. (Im BAF-Framework werden Datensätze nicht gelöscht, sondern deaktiviert, damit sie und die Historie erhalten bleiben.)
Übersetzung
Jeder Listeneintrag kann in jede der angelegten Sprachen übersetzt werden.
Tabellen
create table data_list ( data_list_id varchar(40) not null primary key, category varchar(40), name varchar(40) not null unique, description varchar(80), status int, datechg date, usrchg varchar(40), progchg varchar(40) );
create table data_list_item ( data_list_item_id varchar(40) not null primary key, data_list_id varchar(40) not null, sort int, key varchar(40), value varchar(80), status int, datechg date, usrchg varchar(40), progchg varchar(40) );
create table translate_list_item ( translate_list_item_id varchar(40) not null primary key, data_list_item_id varchar(40) not null, translate_language_id varchar(40) not null, value varchar(80), datechg date, usrchg char(40), progchg varchar2(40) );
Die Tabelle für die Übersetzungen gehört eigentlich in den Namensbereich translate_ und ist hier nur informativ aufgeführt.
Code
xlookup
#rights n=frm r_user=r r_user.admin=w #rights n=admin r_user.admin=w #frm c=xlookup flt=xlookup_flt w=320 #btn y=save s=#save se=c #btn y=cancel s=#cancel se=cp #btn y=back s=#tree_back se=b #btn y=backback s=#tree_fwd se=b #btn y=export s=xlookup_eximport(ex) se=b #btn y=import s=xlookup_eximport(im) se=b #btn c=$T(Add_list) w=120 s=xlookup_add(list) se=b #lbl c=$T(lookup_filter) w=160 #edt n=edt1 w=135 #filter
Das Kommando xlookup ist die Definition eines Standard-Formulars. Leserechte für jeden, Schreibrechte für Administratoren.
xlookup_add
~ $EMPTY($FND(s,category)) #tree_add u=root c=$T(new_list) t=data_list c1=name s="#page_fill d=xlookup_page_list" si=Y ~ $EMPTY($FND(s,data_list_id)) #tree_add u=sel c=$T(new_list) t=data_list c1=name s="#page_fill d=xlookup_page_list" si=Y f_category=$FND(s,category) ~ $EMPTY($FND(s,data_list_item_id)) #tree_add u=selp c=$T(new_list) t=data_list c1=name s="#page_fill d=xlookup_page_list" si=Y f_category=$FND(s,category) ~ #tree_add u=selpp c=$T(new_list) t=data_list c1=name s="#page_fill d=xlookup_page_list" si=Y f_category=$FND(s,category) ~~
Mit xlookup_add wird eine neue Liste angelegt. Je nachdem, wo man sich gerade im Baum befindet, wird dabei Unterschiedliches getan.
Bei der ersten Verzweigung wird keine Kategorie gefunden - es ist also noch kein Eintrag im Baum selektiert. Dann wird der obersten Ebene im Baum (u=root) ein neuer Eintrag hinzugefügt. Bei der zweiten Verzweigung haben wir eine Kategorie (sonst wären wir in der ersten Verzweigung), aber noch keine data_list_id. Wir haben also eine Kategorie selektiert. Unter diese (u=sel) hängen wir nun die neue Liste und setzen gleich die entsprechende Kategorie (f_category=$FND(s,category)) - die der Anwender selbstverständlich abändern kann.
In der dritten Verzweigung haben wir eine Kategorie und eine Liste, aber noch keinen Listeneintrag. Also hängen wir die neue Liste unter den übergeordneten Eintrag des selektierten Eintrags (u=selp - SeletedParent). In der vierten Verzweigung sind wir - mangels Alternativen - auf einem Listeneintrag, also bei den Übersetzungen. Die Kategorie, unter die wir die neue Liste hängen wollen, ist nun zwei Ebenen höher (u=selpp).
xlookup_eximport
~ $ICP(0,ex) #val_set n=1 z=$FILEDIALOG(save,$T(filter_baf),baf) #sql_exporttables fn=$VAL(1) t=data_list t2=data_list_item ~ $ICP(0,im) #val_set n=1 z=$FILEDIALOG(open,$T(filter_baf),baf) #sql_importdefs t=data_list #sql_importdefs t=data_list_item #sql_importtables fn=$VAL(1) t=data_list t2=data_list_item ~~
Der Ex- und Import der Nachschlagelisten ist ziemliches Standard-Vorgehen. Erwähnenswert mag noch sein, dass die Übersetzungen in xtranslate ex- und importiert werden.
xlookup_flt
#tree_clear ~ $NEMPTY($EDT(edt1)) #sql select l.* from data_list l #sql left outer join data_list_item i on l.data_list_id = i.data_list_id #sql left outer join translate_list_item t on i.data_list_item_id = t.data_list_item_id #sql where upper(l.name) like upper(:kedt) #sql or upper(i.cvalue) like upper(:kedt) #sql or upper(t.cvalue) like upper(:kedt) #sql order by l.name; #tree_node u=root t=data_list c1=name s="#page_fill d=xlookup_page_list" o=xlookup_open(list) #tree_fillsql kedt=$EDT(edt1)% ~ #sql select * from data_list order by category, name; #tree_node u=root k=category c1=category nc=Y s="#page_fill d=xlookup_page_category" #tree_node u=last t=data_list c1=name s="#page_fill d=xlookup_page_list" o=xlookup_open(list) #tree_fillsql mex=3 ~~
Wenn ein Filter-Begriff in edt1 eingegeben ist, dann wird nach diesem in den Namen der Liste, den Listeneinträgen sowie in den Übersetzungen der Listeneinträge gesucht; letztlich ist das nur ein entsprechendes SQL-Statement, das die Ergebnisse dann im Baum aufführt.
Gibt es keinen Filter-Begriff, werden die Namen aller Listen geladen und diese nach Kategorien gruppiert. Der Baum wird also zunächst in zwei Ebenen gefüllt. Die Listeneinträge werden dann bei Bedarf nachgeladen (o=xlookup_open(list)). Gibt es nicht mehr als drei Kategorien, werden diese gleich geöffnet (mex=3).
xlookup_open
#sql select data_list_item_id, ckey, cvalue from data_list_item where data_list_id = :kid and status = 1; #tree_node u=exp t=data_list_item c1=ckey c2=cvalue s="#page_fill d=xlookup_page_item" #tree_fillsql kid=$FND(o,data_list_id)
In xlookup_open werden die Einträge einer Liste nachgeladen, wenn der entsprechende Eintrag im Baum geöffnet wird. Die Vorgehensweise ist auch hier sehr "Standard". Erwähnenwert vielleicht noch, dass nur aktive Listeneinträge nachgeladen werden.
Ein Hinweis noch zu $FND(o,data_list_id) - hier brauchen wir nicht den selektierten Eintrag im Baum, sondern denjenigen, der gerade geöffnet wird. Datum ist hier als erster Parameter o und nicht s zu verwenden.
xlookup_page_category
#page n=category #prim as=Y #cat as=Y c=$T(Lists_of_the_category) #grd_seg frc=0 fcc=1 clt=ss mhc=300 n=item #grd_col c1=ID f=data_list_id w=30 y=guid ro=Y #grd_col c1=Name f=name w=200 l=40 #grd_col c1=$T(Description) f=description w=400 wst=500 l=80 r=admin #sql select * from data_list where category = :k_cat order by name #grd_data q=sql t=data_list k_cat=$FND(s,category)
Auf dieser Seite werden alle Listen einer Kategorie mit Namen und Beschreibung gelistet (und können dort bearbeitet werden).
Hinweis zur Beschreibung: Hier haben wir eine Rechtesetzung auf die Spalte (r=admin). Das heißt, Benutzer ohne Admin-Rechte können die Beschreibung noch nicht mal lesen, da sie in der Rechtedefinition in xlookup darauf kein Leserecht bekommen haben.
xlookup_page_item
#page #prim as=Y #cat as=Y c=$T(Translation) #grd_seg frc=0 fcc=1 clt=ss n=grid #grd_col f=translate_list_item_id c1="ID" w=30 y=guid ro=Y nvi=$GUID() #grd_col f=data_list_item_id c1="Data List Item Id" w=0 ro=Y #grd_col f=translate_language_id c1="Translate Language Id" w=0 ro=Y #grd_col f=name c1=$T(Language) ro=Y nd=Y #grd_col f=cvalue c1=$T(Translation) w=300 wst=500 #sql select t.translate_list_item_id, i.data_list_item_id, l.translate_language_id, l.name, t.cvalue #sql from data_list_item i #sql inner join translate_language l on 1 = 1 #sql left outer join translate_list_item t #sql on i.data_list_item_id = t.data_list_item_id and l.translate_language_id = t.translate_language_id #sql where i.data_list_item_id = :kid #grd_data q=sql t=translate_list_item kid=$FND(s,data_list_item_id)
Etwas tricky ist der Code für die Übersetzung der einzelnen Einträge. Die Übersetzungen stehen in der Tabelle translate_list_item, diese benötigt neben der eigenen ID (translate_list_item_id) auf die ID des Listeneintrags (data_list_item_id) und der Sprache (translate_language_id). Die beiden Letztgenannten sind als unsichtbare Spalten (w=0) im Grid angelegt.
Angezeigt dagegen wird der Name der Sprache (f=name), dieser wird jedoch nicht in der Tabelle gespeichert, also muss die Spalte mit nd=Y (NoData) von der Speicherung ausgenommen werden. Da dann eine Änderung auch keinen Sinn ergibt, wird mit ro=Y (ReadOnly) auch die Beschreibbarkeit entfernt.
Das SQL-Statement ist ein Full Join zwischen Listeneinträgen und Sprachen, so dass diese IDs stets vorliegen.
xlookup_page_list
#page #prim as=Y #cat as=Y c=$T(List) #vl_seg cnt=2 clt=ss w1=100 w2=300 wst2=300 c=" " b=H n=list #vl_line c1=ID f2=data_list_id ro2=Y nvic2=$GUID() #vl_line c1=$T(Category) f2=category nvi2=$FND(s,category) l2=40 #vl_line c1=Name f2=name l2=40 #vl_line c1=$T(Description) f2=description l2=80 #vl_data q=t t=data_list kid=$FND(s,data_list_id) #prim as=Y #cat as=Y c=$T(Items) #btns_seg #btns_btn c="$T(Add item)" w=150 cmd="#grd_add i=item f_status=1" #grd_seg frc=0 fcc=1 clt=ss mhc=300 n=item c=" " b=H #grd_col c1=ID f=data_list_item_id w=30 y=guid nvi=$GUID() #grd_col f=data_list_id w=0 nvic=$PVAL(list,data_list_id) nvic_=$FND(s,data_list_id) #grd_col c1=$T(Key) f=ckey w=100 l=40 #grd_col c1=$T(Value) f=cvalue w=200 wst=500 l=80 #grd_col c1=Sort f=csort y=int l=4 #grd_col c1=Status f=status w=80 y=lookup ld=general_status #sql select * from data_list_item where data_list_id = :kid order by csort #grd_data q=sql t=data_list_item kid=$FND(s,data_list_id)
Auf der Seite der Listen können auch gleich deren Einträge bearbeitet werden. Sofern keine Mehrsprachigkeit gewünscht ist, muss man also nicht "tiefer" in den Baum.
Oben werden Name und Beschreibung der Liste in einem VL-Segment gepflegt. Erwähnenswert vielleicht der Paramter nvic2=$GUID(): Liegt keine ID vor (in diesem Fall soll wohl eine neue Liste erstellt werden), so wird eine neue GUID erzeugt. Gleichzeitig wird der Datensatz als inserted gekennzeichnet (somit dann ein INSERT- statt einem UPDATE-Statement), und er wird gleich auch changed gesetzt - damit werden Save- und Cancel-Button verfügbar, so dass die Neuanlage der Liste mit Cancel abgebrochen werden kann.
In dem Grid-Segment werden die einzelnen Einträge bearbeitet. Der Button im darüber liegenden Button-Segment legt einen neuen Datensatz an - da hier nur eine einzelne Prozedur benötigt wird, wird diese gleich in den Parameter cmd geschrieben; damit die Parameter korrekt zugeordnet werden können, sind da allerdings Anführungszeichen erforderlich. Ein neuer Datensatz benötigt nicht nur eine ID, sondern auch eine Referenz auf die Liste. Hier sind parallel zwei Möglichkeiten gezeigt: Die erste funktioniert mit $PVAL und zieht die ID der Liste auf dem VL-Segment. Die zweite Möglichkeit zieht die ID aus dem Baum - das funktioniert auch bei neu angelegten Datensätzen, da die ID schon vor dem Speichern vom VL-Segment in den Baum geschrieben wird.