MESO-XPO 1.0 Help

Benutzerdefinierte Tabellen und Objekte

Workaround für Belegtabelle T026

Sub ErmitteleSpaltenWerte() Dim sql, UserNumber, PaletteOriginal, Spaltennummer, VarNummer UserNumber = right( "000" & cwlstart.CurrentUser.Number, 3) Set myvars = CWLCompany.ModifiedVars sql = "Select * FROM G02W245" & UserNumber & " (NOLOCK) WHERE c062='" & myvars.Value(26,0) & "'" PaletteOriginal = myvars.value(26,506) Palette = 0 Set res = cwlstart.CurrentCompany.Connection.Select(sql) If res>=0 Then ' Benutzerdefinierte Spaltenwerte aus temporärer Grid-Tabelle laden ' Palette Spaltennummer = 156 VarNummer = 506 myvars.value(26,VarNummer) = res.Value("c" & Cstr(Spaltennummer)) ' Rabatttext 1 Spaltennummer = 153 VarNummer = 504 myvars.value(26,VarNummer) = res.Value("c" & Cstr(Spaltennummer)) ' Rabatttext 2 Spaltennummer = 154 VarNummer = 505 myvars.value(26,VarNummer) = res.Value("c" & Cstr(Spaltennummer)) ' Frachtkosten Spaltennummer = 155 VarNummer = 503 myvars.value(26,VarNummer) = res.Value("c" & Cstr(Spaltennummer)) End If res.close Set res = Nothing End Sub 'Ende von (Deklarationen) Sub CWLCompany_OnInsertTable(TableNo) If TableNo = 26 Then Call ErmitteleSpaltenWerte End If End Sub Sub CWLCompany_OnUpdateTable(TableNo) If TableNo = 26 Then Call ErmitteleSpaltenWerte End If End Sub

Datalayer XPDictionary (Metadaten)

Die DataLayer, welche vom DataLayerManager (siehe Herstellen einer Datenverbindung) erzeugt werden, enthalten ein um die benutzerdefinierten Tabellen und Spalten erweitertes XPDictionary (https://docs.devexpress.com/XPO/DevExpress.Xpo.Metadata.XPDictionary), sofern bei der Methode CreateDataLayer die Parameter loadUserdefinedTables (für neue Tabellen) und/oder loadUserdefinedColumns für neue Spalten in Standard-Tabellen gesetzt werden.

Zwar können naturgemäß keine Linq-Abfragen für dynamisch erweiterte Objekte erzeugt werden, jedoch können z.B. XpCollection (https://docs.devexpress.com/XPO/DevExpress.Xpo.XPCollection) Klassen verwendet werden, die dann z.B. an ein GridControl (https://docs.devexpress.com/WindowsForms/DevExpress.XtraGrid.GridControl) gebunden werden können.

Dieses erzeugt dann automatisch eine Column je PersistentProperty - auch derjenigen, die zur Laufzeit erzeugt wurden.

Hier ein Beispiel für die Erzeugung einer XpCollection für die BestelldateiMitte (t026) welche um benutzerdefinierte Spalten erweitert wurde:

using var uow = MesoObjectLayer.GetDataUnitOfWork(); var classInfoT026 = uow.GetClassInfo(typeof(BestelldateiMitte)); var xpCollectionT026 = new XPCollection(uow, classInfoT026); gridControl1.DataSource = xpCollecionT026;

Im DataGrid stehen alle persistenten Properties - inkl. der benutzerdefinierten - zur Verfügung:

Image 20221201 173409

Filterung einer XPCollection mit benutzerdefinierten Spalten

Hier ein Beispiel für die Erzeugung einer XPCollection für den BestelldateiKopf (t025) welche um benutzerdefinierte Spalten erweitert wurde:

var connectionStringSystem = MSSqlConnectionProvider.GetConnectionString( "DEMOSRV01\\DEMO", "meso", "*********", "CWLSYS"); ; using var uowSystem = new SystemUnitOfWork(connectionStringSystem); // Benutzerdefinierte Spalten und Tabellen in das XPDictionary laden using var dal = DataLayerManager.CreateDataLayer(uowSystem, "500M",loadUserdefinedColumns:true, loadUserdefinedTables:true); // ObjectLayer für automatische Filterung auf aktuelles Wirtschaftsjahr var mesoObjectLayer = new MesoObjectLayer(dal, "500M"); using var uow = mesoObjectLayer.GetDataUnitOfWork(); var classInfoT025 = uow.GetClassInfo(typeof(BestelldateiKopf)); var xpCollectionT025 = new XPCollection(uow, classInfoT025, CriteriaOperator.Parse("StartsWith([Kennzeichen],'TS')")); xpCollectionT025.Load(); foreach (var beleg in xpCollectionT025.OfType<BestelldateiKopf>()) { Debug.WriteLine($"Beleg {beleg.Mesoprim} hat Kennzeichen {beleg.GetColumnValueDirect<string>("U000")}"); }

DataLayerManager Hilfsmethoden

LoadUserDefiniedTablesAndColumns

Dadurch werden die in der angegebenen Datenbankverbindungszeichenfolge gespeicherten benutzerdefinierten Tabellen und Spalten aus der Tabelle T132 geladen und in das XPDictionary angefügt.

/// <summary> /// Lädt benutzerdefinierte Tabellen und Spalten in das vorhandene XPDictionary /// </summary> /// <param name="connectionString"></param> /// <param name="dict"></param> public static void LoadUserdefinedTablesAndColumns(string connectionString, XPDictionary dict)

Arbeiten mit abgeleiteten Klassen

Vorteile und Herangehensweise

Wenn benutzerdefinierte Spalten der Mesonic Standard-Tabellen über Vererbung implementiert werden, so hat man den Vorteil, dass die Klasse inkl. benutzerdefinierter Felder im Code vollständig zur Verfügung steht, z.B. für Linq.

Damit das Xpo-Framework jedoch erkennen kann um was für ein Objekt sich ein Datensatz handelt (also um eine Instanz der Basisklasse oder eine Instanz einer abgeleiteten Klasse) ist die Spezifikation mittels ObjectType Spalte erforderlich. Diese Spalte ist wiederum eine Referenz auf die Tabelle XpObjectType (siehe XPObjectType Class | eXpress Persistent Objects | DevExpress Documentation), welche die definierten persistenten Klassen speichert.

Um das Anlegen der notwendigen Tabelle und Spalte in der Mesonic Datenbank kann die Methode CreateObjectTypesForUserDefinedTypes der Klasse DataLayerManager verwendet werden (siehe Verwendete Methoden).

Darüber hinaus müssen die Typen bei der CreateDataLayer Methode im Parameter userdefinedTypes übergeben werden.

Beispiel Ableitungen

Klassendefinitionen
/// <summary> /// Von ArtikelPreise T023 abgeleitet /// </summary> [MapInheritance(MapInheritanceType.ParentTable)] public class ArtikelPreiseMitIstos : ArtikelPreise { public ArtikelPreiseMitIstos(Session session) : base(session) { } private double istosMaterialkosten = default; /// <summary> /// U000 - Istos Materialkosten (kalkulatorisch) /// (Länge 8, SQL Datentyp System.Data.SqlTypes.SqlDouble) /// </summary> [Persistent("U000")] [Display(Name = "Istos Materialkosten (kalkulatorisch)")] public double IstosMaterialkosten { get => istosMaterialkosten; set => SetPropertyValue(nameof(IstosMaterialkosten), ref istosMaterialkosten, value); } } /// <summary> /// Von BestelldateiKopf T025 abgeleitet /// </summary> [MapInheritance(MapInheritanceType.ParentTable)] public class BestelldateiKopfKennzeichen : BestelldateiKopf { public BestelldateiKopfKennzeichen(Session session) : base(session) { } private string kfzkennzeichen = default; /// <summary> /// U000 - KfZ Kennzeichen /// (Länge 20, SQL Datentyp System.Data.SqlTypes.SqlNvarchar) /// </summary> [Persistent("U000")] [Display(Name = "KfZ Kennzeichen")] [Size(20)] public string KfzKennzeichen { get => kfzkennzeichen; set => SetPropertyValue(nameof(KfzKennzeichen), ref kfzkennzeichen, value); } private string anhaenger = default; /// <summary> /// U001 - Anhänger /// (Länge 20, SQL Datentyp System.Data.SqlTypes.SqlNvarchar) /// </summary> [Persistent("U001")] [Display(Name = "Anhänger")] [Size(20)] public string Anhaenger { get => anhaenger; set => SetPropertyValue(nameof(Anhaenger), ref anhaenger, value); } } /// <summary> /// Neue benutzerdefinierte Tabelle T699 in der WinLine-Datenbank /// </summary> [Persistent("T699")] [IsUserdefinedTable] public class Testtabelle : MesoBase { public Testtabelle(Session session) : base(session) { } private string id = default; /// <summary> /// U000 - Id /// (Länge 20, SQL Datentyp System.Data.SqlTypes.SqlNvarchar) /// </summary> [Persistent("U000")] [Display(Name = "Eindeutiger Key")] [Size(10)] [DevExpress.Xpo.Key] public string Id { get => id; set => SetPropertyValue(nameof(Id), ref id, value); } private string wert = default; /// <summary> /// U001 - Wert /// (Länge 255, SQL Datentyp System.Data.SqlTypes.SqlNvarchar) /// </summary> [Persistent("U001")] [Display(Name = "Wert")] [Size(255)] public string Wert { get => wert; set => SetPropertyValue(nameof(Wert), ref wert, value); } }
Exemplarische Verwendung
var connectionStringSystem = MSSqlConnectionProvider.GetConnectionString( "DEMOSRV01\\DEMO", "meso", "meso@demo", "CWLSYS"); ; using var uowSystem = new SystemUnitOfWork(connectionStringSystem); // Abgeleitete persistente Klassen var newTypes = new Type[] { typeof(ArtikelPreiseMitIstos), typeof(BestelldateiKopfKennzeichen), typeof(Testtabelle) }; // Anlegen der ObjectTypes var dict = DataLayerManager.CreateObjectTypesForUserDefinedTypes(connectionStringSystem, newTypes, false); using var dal = DataLayerManager.CreateDataLayer(uowSystem, "500M", additionalTypes: newTypes); // ObjectLayer für automatische Filterung auf aktuelles Wirtschaftsjahr var mesoObjectLayer = new MesoObjectLayer(dal, "500M"); using var uow = mesoObjectLayer.GetDataUnitOfWork(); foreach (var artikelPreis in new XPQuery<ArtikelPreiseMitIstos>(uow).Take(10)) Debug.Print($"{artikelPreis.Preisartikelnummer}:{artikelPreis.IstosMaterialkosten}"); foreach (var beleg in new XPQuery<BestelldateiKopfKennzeichen>(uow).Take(10)) Debug.Print($"{beleg.Mesoprim}:{beleg.KfzKennzeichen}"); // Eigene Tabelle T699 var testobject = uow.GetObjectByKey<Testtabelle>("TestId1"); if (testobject != null) { uow.Delete(testobject); uow.CommitChanges(); } testobject = new Testtabelle(uow) { Id = "TestId1", Wert ="Mein Testwert" }; uow.CommitChanges();

Verwendete Methoden

Der DataLayerManager verwendet hierbei die Methoden DropObjectTypesForUserDefinedTypes und CreateObjectTypesForUserDefinedTypes; insbesondere die Methode DropObjectTypesForUserDefinedTypes ist für Projekte relevant, da die Spalte vor einem Update oder Datenbankupsize oder Erweiterung der Tabellen um eigene Spalten entfernt werden muss.

/// <summary> /// Löscht die Spalte ObjectType aus den Basisklassen der angegebenen benutzerdefinierten Typen. /// Ist der Typ nicht abgeleitet, wird auch nichts durchgeführt /// </summary> /// <param name="connectionStringMesoSystem"></param> /// <param name="userdefinedTypes"></param> public static void DropObjectTypesForUserDefinedTypes(string connectionStringMesoSystem, Type[] userdefinedTypes) /// <summary> /// Erzeugt die XPObjectType Datensätze in der Tabelle XPObjectType (und legt diese ggf. auch an) /// Erweitert bei abgeleiteten Klassen die Basistabellen um die Spalte ObjectType und setzt den ObjecType auf /// die vergebene ID in der Tabelle XPObjectType /// </summary> /// <remarks> /// ACHTUNG: Hierdurch wird die Mesonic Tabellenstruktur um eine Spalte erweitert, die NICHT im Repository bekannt ist /// Das bedeutet, wenn Datenbankupsizes gemacht werden geht diese Spalte ggf. verloren und muss neu erzeugt werden /// /// Um weitere benutzerdefinierte Spalten zu erzeugen MUSS die Spalte vorher entfernt werden. /// Hierfür den <paramref name="dropColumn"/> auf 'true' setzen /// </remarks> /// <param name="connectionStringMesoSystem"></param> /// <param name="userdefinedTypes"></param> /// <param name="dropColumn"></param> /// <returns>Das XPDictionary Objekt welches die benutzerdefinierten Typen enthält</returns> public static XPDictionary CreateObjectTypesForUserDefinedTypes(string connectionStringMesoSystem, Type[] userdefinedTypes, bool dropColumn = false)

CompanyBase - Methoden

Alle Mandantenobjekte leiten von der Klasse CompanyBase ab. Diese stellt folgende Methoden zum Zugreifen auf benutzerdefinierte Spalten bereit:

GetUserdefinedColumnValue

public T GetUserdefinedColumnValue<T>(int columnNumber)

Beispiel zum Ermitteln der benutzerdefinierten Spalte U000 für einen Artikel als int:

Assert.NotNull(artikel.GetUserdefinedColumnValue<int>(0), "Product 50001 has no user definied Column 0 of int");

SetUserdefinedColumnValue

public void SetUserdefinedColumnValue<T>(int columnNumber, T value)

Beispiel zum Setzen der benutzerdefinierten Spalte U000 für einen Artikel auf den Wert “1” als int:

artikel.SetUserdefinedColumnValue<int>(0, 1);
Last modified: 03 March 2025