ELA-Beispiele

Aus TRENZ PartnerNet
Wechseln zu: Navigation, Suche

Es folgen Anwendungsbeispiele der ELA ab Version 2.0

Inhaltsverzeichnis

Allgemein

Eine Aktuelle Version finded sich immer auf P:\ELA

Fieldclasses

Die Feldklassen sind in der Datenklasse eines jeden Containertypes hinterlegt.

 d{ContainerTypName}.FieldClass.m{InternerSteuerelementName}

Feldklassen sind Typensicher. Sie sind unabhängig von einer Containerinstanz.

  • SetIsChanged - Markiert dieses Steuerlement in einen Container als geändert. Beim Aufruf der Save() Methode würde das Steuerelemnt in der Update berücksichtigt werden.
  • GetNullableValue - Gibt den realen Wert des Steuerelements zurück. Dieser kann auch NULL sein.
  • SetNullableValue - Setzt einen Wert für das Steuerelement. Dieser kann auch NULL sein.
  • SetNull - Setzt den Wert des Steuerelements auf NULL.
  • IsUpdated (2 Überladungen) - Gibt zurück ob das Steuerelement im TriggerContext geändert wurde.
  • ContainerTyp - Gibt die ID des Containeres zurück, indem das Steuerelement ist.
  • Kat - Gibt die Lokale Kathegorie(Tab) zurück, indem das Steuerelement ist.
  • Field - Gibt die Steuerelementen ID as Enum zurück.
  • ControlType - Gibt den Steuerelemententyp als Enum zurück. Z.B. Text,DateTime,ContainerControl,DropDown..


Sobald auf eine Fieldclass zugegriffen wird, wird eine neue Instanz der FieldClass erstellt. Es ist daher ratsam z.B. vor einem Schleifendurchlauf eine Referenz zu erstellen und diese weiter zu benutzen.

ELFieldClass<int?> FortschrittbalkenFieldClass = dFelderSpielwiese.FieldClass.mFortschrittbalken;
ELFieldClass<string> TextBoxFieldclass = dFelderSpielwiese.FieldClass.mTextBox_255;
 
foreach (dFelderSpielwiese spielwiese in spielwiesenListe)
{
    FortschrittbalkenFieldClass.SetNullableValue(spielwiese, GetWhateverValue()); // GetWhateverValue() steht in diesen fall für int oder NULL
    TextBoxFieldclass.SetNull(spielwiese); // Setzt das Feld auf NULL
    spielwiese.Save();
}

Prüfung, ob ein Feldinhalt gefüllt ist und auto. Fehlermeldung

Durch ein einfachen aufruf ist es Möglich zu Prüfen, ob ein Feld gesetzt wurde. Wenn nicht, dann generiert die Funktion automatisch eine Fehlermeldung für den User.

  • Zwischen "gefüllt" und "0" kann unterschieden werden.
  • ContainerVerweise können auch geprüft werden.

Beispiel 1: Wenn mTextBox1 nicht gefüllt ist oder bei Zahlenfeldern 0 ist oder mCVerweis1 nicht gesetzt ist, dann wird eine Fehlermeldung an den Benutzer gesendet und die Prozedur beendet.

    dFelderSpielwiese spielwiese = dFelderSpielwiese.Open(Contaier_Id, _eldata);
    if (dFelderSpielwiese.FieldClass.mTextBox1.CheckUnsetAndSendError(spielwiese) ||
        dFelderSpielwiese.FieldClass.mCVerweis1.CheckUnsetAndSendError(spielwiese))
        return;

Beispiel 2: Wenn FehlermTextBox 0 sein darf, aber gefüllt sein muss.

    dFelderSpielwiese spielwiese = dFelderSpielwiese.Open(Contaier_Id, _eldata);
    if (dFelderSpielwiese.FieldClass.mTextBox1.CheckUnsetAndSendError(spielwiese, true))
        return;

Listen:

Laden von Listen
 liste.lFelderSpielwiese_Liste.Load();
 
 liste.lFelderSpielwiese_Liste.LoadWithZZData(
   dFelderSpielwiese.LocalKats.FelderSpielwiese,
   new ELWhereParameter(ELFields.dFelderSpielwiese_mDateTime, 
       ELWhereParameter.eComparer.Größer| ELWhereParameter.eComparer.IsNull, DateTime.Now));
Eine Liste zu einer anderen Kopieren (nur Verweise)
dFelderSpielwiese_Liste liste1 = dFelderSpielwiese_Liste.Open(Container_Id1, _eldata);
dFelderSpielwiese_Liste liste2 = dFelderSpielwiese_Liste.Open(Container_Id2, _eldata);
 
liste1.lFelderSpielwiese_Liste.AddRange(liste2.lFelderSpielwiese_Liste);
Viele Listeneintrage in einer Datenbankanweisung hinzufügen
dFelderSpielwiese_Liste liste = dFelderSpielwiese_Liste.Open(Container_Id, _eldata);
// Container in die Liste einreihen.
liste.lFelderSpielwiese_Liste.Enqueue(spielwiese1);
liste.lFelderSpielwiese_Liste.Enqueue(spielwiese2);
liste.lFelderSpielwiese_Liste.Enqueue(spielwiese3);
// Änderung auf Datenbank übernehmen.
liste.lFelderSpielwiese_Liste.ApplyQueue();

Zkat:

Einstellugen für einen Container
  • Einen Reiter auf nur Lesen setzten. Dieses gilt für alle Benutzer
 dFelderSpielwiese spielwiese = dFelderSpielwiese.Open(Container_Id, _eldata);
 spielwiese.Zkat.Set(dFelderSpielwiese.LocalKats.FelderSpielwiese, ELZkatEigenschaften.NurLesen);
  • Nur für einen Benutzer einen Reiter auf nur Lesen setzten. In diesen Fall für den User miter der UserId 278
 dFelderSpielwiese spielwiese = dFelderSpielwiese.Open(Container_Id, _eldata);
 spielwiese.Zkat.Set(dFelderSpielwiese.LocalKats.FelderSpielwiese, 278,  ELZkatEigenschaften.Erlauben);

Servermessages

OpenContainer:
 spielwiese.Client.Open();

Oder:

  _eldata.Client.OpenContainer(spielwiese);
ShowMessage:
 _eldata.Client.ShowMessage("Hello World!!", ELDatas.Servermessages.eMessageType.Info);

Baumfunktionen

.Net2.0 Helfer:

Da ToList() etc auf IEnumerable erst mit Linq verfügbar ist, gibt es eine Funktionen, die dieses ersetzen kann. Listen oder Arrays können notwendig sein, wenn man z.B. ein Count machen möchte.

 List<ELTree.ELTreeEntry> list = ELTree.ToList(tree.FindNodes(ELContainerTypes.dFelderSpielwiese));

Logging

Das komplette Logging Framework ist unter _eldata.Log zufinden. Es findet nur dann statt, wenn das Projekt als Debug veröffentlicht wurde. Sie beinhalten Standard-Logger die keine weiteren Parameter benötigen. Z.B. ProcedureBegin/ProcedureEnd sowie TriggerBegin/TriggerBegin. Einfache Meldungen könne mit "LogMessage" gespeichert werden. Beispiele:

        [SqlProcedure]
        public static void dAbrechnung_Positionen_BtnWeiter(int container_id, int userid)
        {
            using (ELDatas _eldata = ELDatas.Open(userid))
            {
                _eldata.Log.LogProcedureBegin();
 
                if (jenes == welches) 
                {
                   //do something
                   _eldata.Log.LogMessage("böse: jenes == welches");
                }
 
                _eldata.Log.LogProcedureEnd();
            }
        }

Externe Prozesse

Besonders aus einer SQLCLR-Assembly heraus kann es nützlich sein, Code in einen externen Prozess auszulagern, um z.B. auf Teile des .NET-Frameworks zuzugreifen, die im SQL Server nicht unterstützt werden. Die ELA nimmt dabei das Starten des Prozesses, Übergeben von Datenbankverbindung sowie Containern und ggfs. Rückgeben neuer oder veränderter Container ab. In letzterem Fall wartet der Aufrufer auf das Ergebnis, d.h. die Operation läuft synchron.

Die SQLCLR-Assembly muss UNSAFE sein, da das Starten von Prozessen sonst nicht erlaubt ist. Der Zielprozess muss im Projekt das Kompilier-Symbol ELAExternalProcess definiert haben.

Als Beispiel ein Auszug aus einem Trigger:

foreach (var item in _eldata.GetInserted_ZZTrigger<dFelderSpielwiese>(ELFields.dFelderSpielwiese_mTextBox_Max))
{
	var neueContainer = _eldata.ExternalProcess_Master.Launch(@"C:\Pfad\Zum\Programm.exe", item);
	foreach (var neuerContainer in neueContainer)
		newContainer.OpenContainer();
}

Das Programm ist eine Konsolen-Anwendung, die auf die gleiche ELA-Klasse verweist, und deren Main() wie folgt aussieht:

class Program
{
	static void Main(string[] args)
	{
		ELDatas eldata;
		ELClasses[] containers;
		List<ELClasses> returnContainers = new List<ELClasses>();
 
		if (ELDatas.ExternalProcessManager_Slave.TryParseFromLaunch(out eldata, out containers))
			using (eldata)
			{
				var neuerContainer = dFelderSpielwiese.Create(eldata);
				neuerContainer.Bezeichnung = "test";
				neuerContainer.Save();
 
				returnContainers.Add(neuerContainer);
			}
 
		ELDatas.ExternalProcessManager_Slave.Return(returnContainers.ToArray());
	}
}

_eldata.ExternalProcess_Master.Launch startet also den Prozess synchron und übergibt ein params-Array von Containern. Im gestarteten Zielprozess holen wir uns dann die nötigen Infos durch ELDatas.ExternalProcessManager_Slave.TryParseFromLaunch; hierbei wird eine passende Datenbank-Verbindung mit demselben easyLogic-User aufgebaut. eldata.ExternalProcessManager_Slave.Return schließlich gibt Container an den Aufrufer zurück.

Beim synchronen Aufruf wichtig: da das Zurücksenden via StandardOutput läuft, darf hier nicht manuell reingeschrieben werden; Console.WriteLine() beispielsweise sollte also vermieden werden.

Ein asynchroner Aufruf ist auch möglich (_eldata.ExternalProcess_Master.LaunchAsync); hierbei erhält der Aufrufer jedoch kein Ergebnis.

Windows-Identität im Prozess wechseln

Häufig möchte man, dass der Prozess eine andere Windows-Identität annimmt, um z.B. mit dem Dateisystem zu interagieren. Das nimmt ELDatas.ExternalProcessManager_Slave.WindowsIdentityImpersonation ab. Diese lässt sich am besten via using-Block aufrufen:

System.IO.File.WriteAllText(@"datei1.txt", "1");
 
using (var impersonation = new ELDatas.ExternalProcessManager_Slave.WindowsIdentityImpersonation("benutzer", "domäne", "kennwort"))
	System.IO.File.WriteAllText(@"datei2.txt", "1");
 
System.IO.File.WriteAllText(@"datei3.txt", "1");

datei1.txt und datei3.txt werden mit der Identität des SQL-Servers angelegt (z.B. Netzwerkdienst); datei2.txt jedoch mit der des angegebenen Benutzers benutzer.

Multi-Feld-Funktionen

(Derzeit noch nicht verfügbar.)

Für Feld-Funktionen mit mehreren Rückgabewerten lässt sich im ELA-Creator eine Datei-Vorlage mit den gewünschten Parametern — die man graphisch per Checkliste auswählt — generieren.

Dazu deklariert man zunächst in der Tabelle FieldFunctions die Funktion, z.B. so:

CTypID ControlID FunctionName
1 NULL beispieldb_dFirma_GetMarge

Die ControlID bleibt leer, da mehrere Werte zurückgegeben werden können.

Im ELA-Creator erscheint die Feld-Funktion dann automatisch. In den drei Checklisten gibt man an:

  1. welche Felder als Parameter übergeben werden sollen (mindestens 1),
  2. welche Felder zurückkommen sollen,
  3. sowie welche Eigenschaften zurückkommen sollen (dies und/oder Voriges mindestens 1).

In der dadurch zusätzlich generierten Datei implementiert man den eigentlichen Code, indem man:

  1. in der internal class (hier beispieldb_dFirma_GetMarge_Class) Felder deklariert, die man mit Werten füllen möchte,
  2. in der eigentlichen Funktions-Methode (hier beispieldb_dFirma_GetMarge) auf diese Feld füllt, optional mit Werten aus der Datenbank
  3. in der _Row-Methode (hier beispieldb_dFirma_GetMarge_Row) aus den Feldern heraus ohne Datenbankzugriff Ergebnisse zurückliefert.

Jeweils ein Beispiel:

    public decimal MT;
    public decimal Umsatz;
    public bool AbweichendeMarge;


    MT = c3.Value,
    Umsatz = (c3 > 0 ? c3 * dFirma.Open(c5.Value, _eldata).mzu_fakt_Tagessatz_in_Euro : c1).Value,
    AbweichendeMarge = c4.Value


    c1 = _result.Umsatz;
 
    if (_result.AbweichendeMarge)
    {
        e2 = (int)ELFeldEigenschaften.Aenderbar;
        c2 = SqlDecimal.Null;
    }
    else
    {
        e2 = (int)ELFeldEigenschaften.Kein;
        c2 = _result.Umsatz;
    }

Dies reicht aus, um bei nächster Veröffentlichung dem Client zu erlauben, dynamisch Feld-Werte und -Eigenschaften anhand der Funktion zu setzen.

Ferner generiert der ELA-Creator zwei weitere Methoden zum eigenen Einsatz:

Durch die Apply-Methode (hier Apply_beispieldb_dFirma_GetMarge) kann die Funktion manuell auf einen Container angewandt werden, z.B.:

    var firma = dFirma.Open(123, _eldata);
    dFirma.FieldFunctions.Apply_beispieldb_dFirma_GetMarge(firma, _eldata);

Und durch die ApplyWhereUpdated-Methode (hier ApplyWhereUpdated_beispieldb_dFirma_GetMarge) passiert dies in einem Trigger automatisch für alle Firmen, bei denen sich relevante Felder — also diejenigen, die an die Funktion übergeben werden — geändert haben:

    dFirma.FieldFunctions.ApplyWhereUpdated_beispieldb_dFirma_GetMarge(_eldata);

Dies wendet die Funktion komfortabel und effizient (da mengenorientiert) an.

Trigger Features

Zcontainer

Container Fremden Types austauschen
// wenn in dFelderSpielwiese_Liste ein Container vom Typ dDropContainer hinzugefügt wird.
foreach (var item in _eldata.GetInserted_ZConTrigger_ToReplace<dDropContainer, dFelderSpielwiese, dFelderSpielwiese_Liste>
                                                              ((int)dFelderSpielwiese_Liste.GlobalKats.FelderSpielWiese_Liste))
{
    item.ResultDatensatz.mTextBox_255 = "Hello";
    item.ResultDatensatz.mDD_Verweis_auf_Spielwieder = item.SourceDatensatz;
    item.Zuordnung.lFelderSpielWiese_Liste.Add(item);
    item.ResultDatensatz.Save();
}

X_Zcontainer

Auf Löschen reagieren

Beispiel: Wird ein Mitarbeiter aus einer Firma gelöscht, dann soll der Verweis auf die Firma entfernt werden. Achtung: Mit dieser Methode steht die UserID und damit Servernachrichten nicht zur verfügung.

foreach (var item in _eldata.GetDeleted_ZConTrigger<dMitarbeiter, dFirma>
                                                            ((int)dFirma.GlobalKats.Mitarbeiter_Liste))
{
    item.Datensatz.mFirma = null;
    item.Datensatz.Save();
}
Auf Löschen von Containern (nur aus easyLogic) Reagieren

Dieser Trigger wird nur aufgerufen, wenn in easyLogic ein Container in einer Liste gelöst wird. Wenn in einer Prozedure ein Container aus einer Liste entfernt wird, wird dieses nicht aufgerufen. Die UserID ist bei dieser Funktion zugreifbar.

foreach (var item in _eldata.GetInserted_XZConTrigger<dFelderSpielwiese, dFelderSpielwiese_Liste>
                                                            ((int)dFelderSpielwiese_Liste.GlobalKats.FelderSpielWiese_Liste))
{
    // Die Liste nur laden, wenn Sie nocht nicht geladen wurde.
    if (!item.Zuordnung.lFelderSpielWiese_Liste.LoadedComplete)
        item.Zuordnung.lFelderSpielWiese_Liste.Load();
 
    item.Zuordnung.mAnzahl = item.Zuordnung.lFelderSpielWiese_Liste.Count;
 
    // Servernachricht schicken, um das Steuerelement neu zuladen.
    item.Zuordnung.Client.RefreshFields(ELFields.dFelderSpielwiese_mAnzahl);
}

ZZ-Tabellen

Verhindern das Tigger sich gegenseitig immer wieder aufrufen
if (_eldata.GetTriggerNestlevel() > 1)
   return;
Alle Datensatze durchlaufen

Note: Bei allen Bespielen wird die UserId automatisch vom aensab gesetzt.

foreach (var item in _eldata.GetInserted_ZZTrigger<dFelderSpielwiese>())
Rausfinden, ob sich eine Spalte geändert hat
ELFieldClass<string> TextBoxFieldclass = dFelderSpielwiese.FieldClass.mTextBox_255;
foreach (var item in _eldata.GetInserted_ZZTrigger<dFelderSpielwiese>())
{
    if (TextBoxFieldclass.IsUpdated(item))
    {
    }
}
Datensatze durchlaufen, wo ein bestimmtes Feld geändert wurden

Note: Bei allen Bespielen wird die UserId automatisch vom aensab gesetzt.

//Nur Datensäzte, bei denen das Feld mTextBox_Max geändert wurde
foreach (var item in _eldata.GetInserted_ZZTrigger<dFelderSpielwiese>(ELFields.dFelderSpielwiese_mTextBox_Max))
 
//gleiche
foreach (var item in _eldata.GetInserted_ZZTrigger<dFelderSpielwiese>(
    new ELWhereParameter(ELFields.dFelderSpielwiese_mTextBox_Max, ELWhereParameter.eComparer.IsUpdated, null)))
 
//Nur Datensäzte, bei denen mTextBox_Max oder mTextBox_255 verändert wurden.
foreach (var item in _eldata.GetInserted_ZZTrigger<dFelderSpielwiese>(
    ELWhereParameter.eCombineType.OR,
    new ELWhereParameter(ELFields.dFelderSpielwiese_mTextBox_Max, ELWhereParameter.eComparer.IsUpdated, null),
    new ELWhereParameter(ELFields.dFelderSpielwiese_mTextBox_255, ELWhereParameter.eComparer.IsUpdated, null)))
Bedingtest setzten von Feldern
public void Update_Allgemein_intern()
{
    foreach (var spielwiese in _eldata.GetInserted_ZZTrigger<dFelderSpielwiese>(
        ELWhereParameter.eCombineType.OR,
        new ELWhereParameter(ELFields.dFelderSpielwiese_mTextbox_Int, ELWhereParameter.eComparer.IsUpdated, null),
        new ELWhereParameter(ELFields.dFelderSpielwiese_mTextbox_Decimal, ELWhereParameter.eComparer.IsUpdated, null)))
    {
 
        if (spielwiese.mTextbox_Int == 0)
            spielwiese.mTextbox_Int = 1234; // wert vorbesetzten;
 
        if (spielwiese.mTextbox_Decimal == 0)
            spielwiese.mTextbox_Int = 4321; // wert vorbesetzten;
 
        spielwiese.Save(); // Speicher findet intern nur statt, wenn ein Feld verändert wurde.
    }
}
Updated Datensatz wieder zurücksetzten
foreach (var spielwiese in _eldata.GetInserted_ZZTrigger<dFelderSpielwiese>())
{
    if (WhatEverEvilHappend)
    {
        dFelderSpielwiese deleted = spielwiese.GetDeleted(dFelderSpielwiese.LocalKats.FelderSpielwiese);
        deleted.SetAllChanged();
        deleted.Save();
    }
}
Datensatz in Liste vom ContainerVerweis bei Änderung löschen / hinzufügen
    foreach (dFelderSpielwiese spielwiese in _eldata.GetInserted_ZZTrigger<dFelderSpielwiese>(
                new ELWhereParameter(ELFields.dFelderSpielwiese_mContainerVerweis, ELWhereParameter.eComparer.IsUpdated, null)))
    {
        //Alternativ wäre auch eine abfrage per FieldClass möglich
 
        // Holt die Werte aus der Deleted Tabelle
        // der delete-tablle muss gesagt werden, in welche Werte geladen werten könne, 
        // sprich in welcher Tabelle der Trigger sich befindet.
        dFelderSpielwiese deleted = spielwiese.GetDeleted(dFelderSpielwiese.LocalKats.FelderSpielWiese);
 
        if (spielwiese.mContainerVerweis_CID != deletet.mContainerVerweis_CID)
        {
            if (deleted.mContainerVerweis_CID > 0)
                deleted.mContainerVerweis.lFelderSpielWiese_Liste.Remove(deleted);
 
            if (spielwiese.mContainerVerweis_CID > 0)
                spielwiese.mContainerVerweis.lFelderSpielWiese_Liste.Add(spielwiese);
        }
    }
Meine Werkzeuge