kannengi1
New Creator

RULES: Zugriff auf Datensatz aus FS_DATASET

Jump to solution

Hallo,

ich habe folgendes Problem:
In einem Formular kann ich einen Datensatz aus einer Mitarbeitertabelle auswählen (FS_DATASET). Mit Regeln möchte ich erreichen, dass die ID des ausgewählten Mitarbeiters automatisch in ein anderes Feld des Formulars geschrieben wird (vom Typ CMS_INPUT_NUMBER).
Hintergrund: Das Formular gehört zu einer Tabellenvorlage ("Mitarbeiterdokumente") und auf der Mitarbeiter-Detailseite (Content Projection) brauche ich ein ContentSelect, das mir die richtige Zeile aus der Tabelle "Mitarbeiterdokumente" liefert. Beide Tabellen sind in unterschiedlichen Datenbankschemata (eine sogar extern), so dass ich beim ContentSelect nicht über richtige "FirstSpirit-Relationen" gehen kann.

Meine Regel funktioniert aber nicht und loggt eine Warning:
WARN 12.01.2022 15:33:57.834 (de.espirit.firstspirit.forms.rules.Rule): There is no fact 'VALUE' for item 'tt_employee.id'!

Hier das Formular der Tabellenvorlage:

<CMS_MODULE>

  <FS_DATASET
    name="tt_employee"
    allowDelete="no"
    allowEdit="no"
    allowEmpty="no"
    allowNew="no"
    hFill="yes"
    mode="sheet"
    useLanguages="no">
    <LANGINFOS>
      <LANGINFO lang="*" label="Employee"/>
    </LANGINFOS>
    <SOURCES>
      <CONTENT name="vwintranettflemployees"/>
    </SOURCES>
  </FS_DATASET>

  <CMS_INPUT_NUMBER name="tt_employee_id" hFill="yes" singleLine="no" useLanguages="no">
    <LANGINFOS>
      <LANGINFO lang="*" label="Employee ID" description=""/>
    </LANGINFOS>
  </CMS_INPUT_NUMBER>

</CMS_MODULE>

Zugehörige Regel:

<RULES>
	<RULE>
		<WITH>
			<PROPERTY name="VALUE" source="tt_employee.id"/>
		</WITH>
		<DO>
			<PROPERTY name="VALUE" source="tt_employee_id"/>
		</DO>
	</RULE>
</RULES>

 

Ein ähnlicher Fall (sehr alt) wurde bereits hier https://community.crownpeak.com/t5/Questions-Answers/Externe-und-interne-Datenquelle-verkn%C3%BCpfen... beschrieben, aber nicht die Lösung mit Regeln behandelt.

Muss ich über einen ValueService gehen? In der Doku steht aber, dass der ValueService Werte aus FS_DATASET nicht verabeiten kann.
Oder ein Skript, das ich einen FS_BUTTON hänge? Ich hätte es halt gern automatisch..

Danke für Euren Rat!

Gruß,
Benny

 

0 Kudos
1 Solution

Accepted Solutions

Hallo Benny,

ja, jetzt versteh ich das eigentliche Problem.

Lösungsansätze könnten sein:

Anstelle einer FS_DATASET Eingabekomponente eine CMS_INPUT_COMBOBOX (mit CMS_INLUDE_OPTIONS) nehmen. Deren VALUE müsste eine Zahl (Long oder Integer, abhängig von Spaltenkonfiguration in der Datenbank) sein, die man dann einfach per Regel auf eine CMS_INPUT_NUMBER umbiegen kann. Nachteile: bereits gepflegte Daten sind nicht kompatibel, Eingabekomponente ist schlechter zu handhaben für die Nutzer.

In der contentSelect Funktion mittels LIKE die Persistenz der FS_DATASET Eingabekomponente abfragen. Da diese auf eine externe Tabelle zeigt, müsste da so etwas wie <KEY><ITEM>#ID</ITEM></KEY> drin stehen, wobei #ID die ID des Datensatzes aus der externen Tabelle ist. Da müsstest Du dann mal probieren, wie man den CMS_VALUE_PARAM sauber zusammensetzen muss. Entweder "&gt; + #row.Id + &lt;" oder "\> + #row.Id + \<" oder evtl. auch den String erst im Template zusammensetzen und dann die contentSelect Funktion in einer Formatvorlage nutzen (Konfiguration und Ausgabe), der der zusammengesetzte Parameter übergeben wird. {einfacher wäre es, wenn die ID eindeutig ist - also alle IDs dieselbe Anzahl an Stellen haben. Also ausgeschlossen ist, dass eine ID eine Teilmenge einer anderen ID ist. Halte ich aber für nicht realistisch} Nachteile: Ziemliches "Gefummel" um die Daten sauber abfragen zu können, LIKE Statements sind weniger performant

Einen eigenen VALUE Service schreiben, der die FS_DATASET Eingabekomponente ausliest, daraus die ID extrahiert und diese in die andere Eingabekomponente schreibt. Wenn man den an den Focus der FS_DATASET Eingabekomponente knüpft und den Wert der anderen Eingabekomponente nur ändert, wenn diese den Wert noch nicht hat, sollte das sauber funktionieren. 

Ein Skript/Modul schreiben, welches den Identifier in eine versteckte Eingabekomponente schreibt. Dieses vor jeder Generierung ausführen. Wenn man sich für diese Lösung entscheidet, sollte sichergestellt werden, dass die versteckte Eingabekomponente nicht jedes mal neu geschrieben wird. Beispielsweise kann diese per Regel bei jedem manuellen Bearbeiten (onlock) geleert werden. Dann braucht sie nur neu gesetzt zu werden, wenn sie nicht gesetzt ist. Nachteile: wieder "Gefummel", um das sauber und performant hinzubekommen. Funktioniert in der Vorschau der externen Datensätze erst nach der nächsten Generierung (warum, weiß in zwei Monaten niemand mehr 😉

Ich hoffe, dass hilft irgendwie weiter 🙂
Holger

View solution in original post

0 Kudos
6 Replies
hoebbel
Crownpeak employee

Hallo Benny,

ich antworte einfach mal mit einer Gegenfrage - wozu brauchst Du die CMS_INPUT_NUMBER Eingabekomponente, wenn der Datensatz doch in der FS_DATASET Eingabekomponente ausgewählt ist?

Hol Dir doch einfach von dort die ID und verwende die in der contentSelect Funktion: tt_employee.entity.fs_id müsste hier funktionieren.

Viele Grüße
Holger

0 Kudos

Hallo Holger,

ich verstehe nicht ganz wie Du das meinst - die Content Projektion für die Mitarbeiterdetailseiten geht ja auf eine andere Tabelle (externe Datenbank - die im FS_DATASET referenziert wird) und von dort muss ich mir ja genau die Datensätze aus der Tabelle für "Mitarbeiterdokumente" holen, in denen der betreffende Mitarbeiter ausgewählt ist.

Ich wollte das so machen:

	<CMS_FUNCTION name="contentSelect" resultname="fr_employeeDocuments">
		<CMS_PARAM name="schema" value="tfl" />
		<CMS_VALUE_PARAM name="employee_id" value="#row.Id" />
		<QUERY entityType="employee_documents">
			<FILTERPARAM parameter="employee_id" datatype="java.lang.Long"/>
			<EQ attribute="employee_id" datatype="java.lang.Long" parameter="employee_id"/>
		</QUERY>
	</CMS_FUNCTION>

Oder meinst Du ich soll bei dem contentSelect gar keinen Filter angeben und dann einfach in einer Schleife die employee ID abfragen?

Danke und Gruß,

Benny

0 Kudos

Hallo Benny,

ich habe es so verstanden:
Du hast eine Tabellenvorlage mit der FS_DATASET Eingabekomponente und der contentSelect Funktion.
In der ContentSelect Funktion willst Du Datensätze aus einem anderen Schema ausgeben. Dafür musst Du als Filterparameter die ID des in der FS_DATASET ausgewählten Datensatzes nutzen.

Die contentSelect Funktion könnte dann beispielsweise so aussehen.

Hinweis: als Wert für den CMS_VALUE_PARAM kannst Du eine beliebige Variable nutzen, die zum Ausführungszeitpunkt der Funktion im Kontext ist. Wenn Du die Variable im Template mittels $CMS_SET(...)$ erzeugst, würde es so nicht funktionieren. Dann müsste die contentSelect Funktion (inkl. deren Ausgabe) in ein Formatemplate überführt werden, was nach dem Setzen der Variable per CMS_RENDER aufgerufen wird. 

	<CMS_FUNCTION name="contentSelect" resultname="fr_employeeDocuments">
		<CMS_PARAM name="schema" value="tfl" />
		<CMS_VALUE_PARAM name="employee_id" value="tt_employee.entity.fs_id" />
		<QUERY entityType="employee_documents">
			<FILTERPARAM parameter="employee_id" datatype="java.lang.Long"/>
			<EQ attribute="employee_id" datatype="java.lang.Long" parameter="employee_id"/>
		</QUERY>
	</CMS_FUNCTION>

Voraussetzung ist allerdings, dass die FS_DATASET Eingabekomponente in der Tabellenvorlage vorhanden und korrekt gemappt ist. {Ich erwähne das, da die Vorlage zum Pflegen ja eine andere Vorlage als die zur Ausgabe verwendet werden kann}. 

Oder anders herum ausgedrückt - Du kannst die FS_ID des Datensatzes direkt aus der FS_DATASET Eingabekomponente bekommen. Irgendwelche Konstrukte über Regeln sind nur notwendig, wenn Du die ID über die Regeln prüfen willst bzw. die ID benötigst, um für andere Eingabekomponente (z.B. FS_INDEX) die Auswahlliste per Regel einschränken willst. Das ist aber laut der initialen Beschreibung nicht dein Anwendungsfall.

Viele Grüße
Holger

0 Kudos

Hallo Holger,

Leider habe ich mich anscheinend nicht klar genug ausgedrückt.
Deshalb erkläre ich die Anforderung noch ein wenig ausführlicher:

Es gibt zwei Datenquellen, eine externe und eine interne:

  • Datenquelle "Mitarbeiter" (extern, read-only, nicht von FirstSpirit gemanaged)
    - aus dieser Datenquelle wird per Content Projection für jeden Mitarbeiter eine Mitarbeiter-Detailseite erzeugt
    - Tabellenvolage nicht relevant, da nichts gepflegt werden kann

    Anforderung war jetzt, die Mitarbeiterdaten anzureichern mit Dokumenten, die in FirstSpirit liegen und diese als Linkliste auf der Seite des jew. Mitarbeiters auszugeben.

    Dazu habe ich eine neue Datenquelle "Mitarbeiterdokumente" angelegt:
  • Datenquelle "Mitarbeiterdokumente" (von FirstSpirit gemanaged)
    - in einem Datensatz wird dem per FS_DATASET aus der externen Datenquelle (s.o.) ausgewählten Mitarbeiter ein oder mehrere Dokumente zugeordnet

    zugehörige Tabellenvorlage "Mitarbeiterdokumente":

 

<CMS_MODULE>

  <FS_DATASET
    name="tt_employee"
    allowDelete="no"
    allowEdit="no"
    allowEmpty="no"
    allowNew="no"
    hFill="yes"
    mode="sheet"
    useLanguages="no">
    <LANGINFOS>
      <LANGINFO lang="*" label="Employee"/>
    </LANGINFOS>
    <SOURCES>
      <CONTENT name="vwintranettflemployees"/>
    </SOURCES>
  </FS_DATASET>

  <CMS_INPUT_NUMBER name="tt_employee_id" hFill="yes" singleLine="no" useLanguages="no">
    <LANGINFOS>
      <LANGINFO lang="*" label="Employee ID" description=""/>
    </LANGINFOS>
  </CMS_INPUT_NUMBER>

  <FS_CATALOG name="tt_linklist" useLanguages="no">
    <LANGINFOS>
      <LANGINFO lang="*" label="Document Link List" description=""/>
    </LANGINFOS>
    <TEMPLATES type="link">
      <TEMPLATE uid="file_link"/>
    </TEMPLATES>
  </FS_CATALOG>

</CMS_MODULE>

 


Zugehörige Regel:

 

<RULES>
	<RULE>
		<WITH>
			<PROPERTY name="VALUE" source="tt_employee.id"/>
		</WITH>
		<DO>
			<PROPERTY name="VALUE" source="tt_employee_id"/>
		</DO>
	</RULE>
</RULES>

 

 

Jetzt wieder zurück zur Datenquelle "Mitarbeiter" (extern), Ausgabe:
Hier will ich jetzt ja auf den Mitarbeiterdetailseiten die für den jew. Mitarbeiter gepflegten Dokumente als Link ausgeben - die ja, von der Content Projection aus gesehen, in einer anderen Tabelle liegen (nämlich in der Mitarbeiterdokumente-Datenquelle).
Deshalb wollte ich dieses Contentselect machen, wo ich die aktuelle #row.Id (fs_id gibt's nicht, da nicht von FirstSpirit gemanaged) als Filter nutzen will, um den richtigen Datensatz aus der Mitarbeiterdokumente-Tabelle rauszuholen - damit das funktioniert, muss ich aber die ID in der Mitarbeiterdokumente-Tabelle in einer eigenen Spalte haben (eben der Spalte "employee_id", die ich per obiger Regel setzen will):

 

<CMS_FUNCTION name="contentSelect" resultname="fr_employeeDocuments">
	<CMS_PARAM name="schema" value="tfl" />
	<CMS_VALUE_PARAM name="employee_id" value="#row.Id" />
	<QUERY entityType="employee_documents">
		<FILTERPARAM parameter="employee_id" datatype="java.lang.Long"/>
		<EQ attribute="employee_id" datatype="java.lang.Long" parameter="employee_id"/>
	</QUERY>
</CMS_FUNCTION>

 

 

Ich hoffe Du verstehst jetzt?

Danke und Gruß,
Benny

0 Kudos

Hallo Benny,

ja, jetzt versteh ich das eigentliche Problem.

Lösungsansätze könnten sein:

Anstelle einer FS_DATASET Eingabekomponente eine CMS_INPUT_COMBOBOX (mit CMS_INLUDE_OPTIONS) nehmen. Deren VALUE müsste eine Zahl (Long oder Integer, abhängig von Spaltenkonfiguration in der Datenbank) sein, die man dann einfach per Regel auf eine CMS_INPUT_NUMBER umbiegen kann. Nachteile: bereits gepflegte Daten sind nicht kompatibel, Eingabekomponente ist schlechter zu handhaben für die Nutzer.

In der contentSelect Funktion mittels LIKE die Persistenz der FS_DATASET Eingabekomponente abfragen. Da diese auf eine externe Tabelle zeigt, müsste da so etwas wie <KEY><ITEM>#ID</ITEM></KEY> drin stehen, wobei #ID die ID des Datensatzes aus der externen Tabelle ist. Da müsstest Du dann mal probieren, wie man den CMS_VALUE_PARAM sauber zusammensetzen muss. Entweder "&gt; + #row.Id + &lt;" oder "\> + #row.Id + \<" oder evtl. auch den String erst im Template zusammensetzen und dann die contentSelect Funktion in einer Formatvorlage nutzen (Konfiguration und Ausgabe), der der zusammengesetzte Parameter übergeben wird. {einfacher wäre es, wenn die ID eindeutig ist - also alle IDs dieselbe Anzahl an Stellen haben. Also ausgeschlossen ist, dass eine ID eine Teilmenge einer anderen ID ist. Halte ich aber für nicht realistisch} Nachteile: Ziemliches "Gefummel" um die Daten sauber abfragen zu können, LIKE Statements sind weniger performant

Einen eigenen VALUE Service schreiben, der die FS_DATASET Eingabekomponente ausliest, daraus die ID extrahiert und diese in die andere Eingabekomponente schreibt. Wenn man den an den Focus der FS_DATASET Eingabekomponente knüpft und den Wert der anderen Eingabekomponente nur ändert, wenn diese den Wert noch nicht hat, sollte das sauber funktionieren. 

Ein Skript/Modul schreiben, welches den Identifier in eine versteckte Eingabekomponente schreibt. Dieses vor jeder Generierung ausführen. Wenn man sich für diese Lösung entscheidet, sollte sichergestellt werden, dass die versteckte Eingabekomponente nicht jedes mal neu geschrieben wird. Beispielsweise kann diese per Regel bei jedem manuellen Bearbeiten (onlock) geleert werden. Dann braucht sie nur neu gesetzt zu werden, wenn sie nicht gesetzt ist. Nachteile: wieder "Gefummel", um das sauber und performant hinzubekommen. Funktioniert in der Vorschau der externen Datensätze erst nach der nächsten Generierung (warum, weiß in zwei Monaten niemand mehr 😉

Ich hoffe, dass hilft irgendwie weiter 🙂
Holger

0 Kudos

Vielen Dank Holger für die Erläuterung der Optionen...

die ohne Gefummel werde ich mal ausproberen!

Gruß,

Benny

0 Kudos