Für Projekte in .NET verwende ich sehr gerne die Steuerelemente von DevExpress (Englisch). Darüber hinaus ist DevExpress XPO als Datenbank-Abstraktionsebene sehr nützlich.
Jedoch stieß ich in einem aktuellen Projekt auf ein sehr seltsames Problem:
Bei einigen Formularen (seltsamerweise nicht bei allen) wurde eine sehr teure SQL-Abfrage an das Datenbank-Backend gesendet während das Formular geladen wurde. Es war im Prinzip eine SQL-Abfrage, die sämtliche (und ich meine wirklich alle) Datenzeilen von der Datenbank lud, was offensichtlich keine besonders gute Idee ist. Aber wie geschrieben war das nicht für alle Formulare der Fall: Bei den anderen Formularen wurde erwartungsgemäß nur das aktuelle Datenobjekt (die aktuelle Zeile der Tabelle) geladen.
Natürlich kontaktierte ich zunächst den immer sehr schnellen und hilfreichen DevExpress-Support. Sie haben untersucht, was die Datenabfrage auslöst und festgestellt, dass die Eigenschaft XPCollection.Count von dem CurrencyManager nach dem Methodenaufruf Control.UpdateBindings angefordert wird. Da dies etwas innerhalb des .NET Frameworks ist, konnten sie daran leider nichts ändern.
Sie schlugen vor die XPCollection nicht zur Design-Zeit zu setzen. Dies hätte jedoch bedeutet, dass ich die Formulare nicht mehr mit dem Windows-Formular-Designer erstellen könnte. Das wäre ganz schlecht, da ich viele große Formular in diesem Projekt habe, die ich sicherlich nicht alle im Quelltext erstellen möchte.
Ich fand jedoch einen andere Weg – ich nenne das nicht eine Lösung, nur ein Work-Around –, um den Designer weiterhin verwenden zu können:
Hierzu habe ich einfach zwei Batch-Dateien (unter Verwendung des Kommandozeilen-Ersetzungstools namens FART (Englisch)) geschrieben: Eine, die ausgeführt wird bevor das Build beginnt und sicherstellt, dass keine XPCollection innerhalb der Methode InitializeComponent initialisiert wird (und dabei einfach die Quelltextzeilen auskommentiert), und eine zweite, die nach dem Build läuft und die Änderungen wieder rückgängig macht.
Hier ist der Inhalt der Pre-Build-Batch-Datei:
%1Tools\fart.exe -r -C "%1*.designer.cs" "this.xpKern = new DevExpress.Xpo.XPCollection(this.components);" "\x2f\x2fthis.xpKern = new DevExpress.Xpo.XPCollection(this.components);"
%1Tools\fart.exe -r -C "%1*.designer.cs" "((System.ComponentModel.ISupportInitialize)(this.xpKern)).BeginInit();" "\x2f\x2f((System.ComponentModel.ISupportInitialize)(this.xpKern)).BeginInit();"
%1Tools\fart.exe -r -C "%1*.designer.cs" "this.xpKern.ObjectType = typeof(Administration.Daten.Kern);" "\x2f\x2fthis.xpKern.ObjectType = typeof(Administration.Daten.Kern);"
%1Tools\fart.exe -r -C "%1*.designer.cs" "this.xpKern.Session = this.unitOfWork;" "\x2f\x2fthis.xpKern.Session = this.unitOfWork;"
%1Tools\fart.exe -r -C "%1*.designer.cs" "((System.ComponentModel.ISupportInitialize)(this.xpKern)).EndInit();" "\x2f\x2f((System.ComponentModel.ISupportInitialize)(this.xpKern)).EndInit();"
@exit 0
Und die Post-Build-Datei, welche die Änderungen wieder rückgängig macht:
%1Tools\fart.exe -r -C "%1*.designer.cs" "\x2f\x2fthis.xpKern = new DevExpress.Xpo.XPCollection(this.components);" "this.xpKern = new DevExpress.Xpo.XPCollection(this.components);"
%1Tools\fart.exe -r -C "%1*.designer.cs" "\x2f\x2f((System.ComponentModel.ISupportInitialize)(this.xpKern)).BeginInit();" "((System.ComponentModel.ISupportInitialize)(this.xpKern)).BeginInit();"
%1Tools\fart.exe -r -C "%1*.designer.cs" "\x2f\x2fthis.xpKern.ObjectType = typeof(Administration.Daten.Kern);" "this.xpKern.ObjectType = typeof(Administration.Daten.Kern);"
%1Tools\fart.exe -r -C "%1*.designer.cs" "\x2f\x2fthis.xpKern.Session = this.unitOfWork;" "this.xpKern.Session = this.unitOfWork;"
%1Tools\fart.exe -r -C "%1*.designer.cs" "\x2f\x2f((System.ComponentModel.ISupportInitialize)(this.xpKern)).EndInit();" "((System.ComponentModel.ISupportInitialize)(this.xpKern)).EndInit();"
@exit 0
Das @exit 0
am Ende dieser ist wichtig, da ansonsten ein Code 2 zurückgegeben wird (warum auch immer) und das Visual-Studio-Build-System sich bei jedem Build darüber beschwert.
Nun müssen Sie nur doch diese Batch-Dateien in den Visual-Studio-Buildereignissen mit
$(ProjectDir)Tools\PreBuild.bat $(ProjectDir)
beziehungsweise
$(ProjectDir)Tools\PostBuild.bat $(ProjectDir)
aufrufen.
Ich weiß, dass dies keine besonders gute “Lösung” ist, aber das war die einzige Idee, die ich hatte, dass ich weiterhin den Formular-Designer verwenden kann und trotzdem diese teuren SQL-Anfragen vermeide.
Hatten Sie bereits einmal dieses Problem und vielleicht sogar eine bessere Lösung dafür? Ich freue mich über jeden anderen Vorschlag zu diesem Thema!