Das Notes Forum

Domino 9 und frühere Versionen => ND8: Entwicklung => Thema gestartet von: schroederk am 09.11.11 - 08:31:37

Titel: Lotusscript Optimierung
Beitrag von: schroederk am 09.11.11 - 08:31:37
Hallo zusammen,

ich würde gerne von Euch über den folgende Code schauen lassen. Dieser wird über Web aufgerufen und soll aus dem Raum-und Reservierungsplaner mit angegebenem Datum und Raumname die vorhandenen Termine auflisten.
Der Code hat sicher noch Optimierungspotential und ich würde gerne konstruktive Kritik erfahren, wie ich was besser machen kann.
Die Ausgabe ist im Moment noch sehr spartanisch, ich weiß aber auch noch nicht, ob ich die Werte Komma-separiert übertrage und vom Web aus die Aufbereitung vornehme oder ob ich das schon im Script machen soll.

Zitat
Option Public
Option Declare

Sub Initialize
   Dim s As New NotesSession
   Dim db As NotesDatabase
   Dim view As NotesView
   Dim doc As NotesDocument
   Dim vc As NotesViewEntryCollection
   Dim str_datum, str_aktdatum, str_raumname As String
   Dim col As NotesDocumentCollection
   Dim arg As String, p1 As Long
   Dim argarray As Variant
   Dim todaysdate As New NotesDateTime("Today")
   Dim startdatum, enddatum, raumname As String
   Dim teilnehmer As String
   Dim besprechtitel As String

   str_aktdatum = todaysdate.DateOnly

   On Error GoTo processError

   arg = s.DocumentContext.Query_String(0)
   p1 = InStr(arg, "&")
   arg = LCase(Mid$(arg, p1 + 1))                     ' alle Parameter aus der URL extrahieren
   argarray = Evaluate({@Explode("} & arg & {"; "&")})      ' jeden Parameter trennen und in Array speichern

   str_datum = argarray(0)
   str_raumname = argarray(1)
   If str_datum = "" Then                           ' Wenn kein Datum angegeben wurde, dann aktuelles Datum wählen
      str_datum = str_aktdatum
   End if
 
   Set db = s.GetDatabase("MAILSERVER/SRV/Group", "Besprech.nsf", False)
   If Not db.IsOpen Then Call db.Open("", "")

   Set view = db.GetView("Reservierungen nach Datum")         ' Alle Reservierungen nach Datum
   Set doc = view.GetFirstDocument

   While Not(doc Is Nothing)                           ' Alle Dokumente in Ansicht abarbeiten
      startdatum = Left(doc.GetItemValue("StartDate")(0),10)
      enddatum = Left(doc.GetItemValue("EndDate")(0),10)
      raumname = doc.GetItemValue("Room")(0)
      If raumname <> "" then
         raumname = Left(raumname,InStr(raumname,"/")-1)
      End if
      teilnehmer = doc.GetItemValue("Capacity")(0)
      besprechtitel = doc.GetItemValue("Purpose")(0)
      If str_datum = startdatum Or str_datum = enddatum Then
         If str_raumname = "" Or str_raumname = LCase(raumname) Then
            Print startdatum, enddatum, raumname, teilnehmer, besprechtitel, "<br>"
         End if
      End If
      Set doc = view.GetNextDocument(doc)
   Wend   
   Exit Sub
processError:
   Print "Fehler " & Str(Err) & ": " & Error$ & " in Zeile " & Str(Erl)
   Exit Sub    
End Sub
Titel: Re: Lotusscript Optimierung
Beitrag von: Peter Klett am 09.11.11 - 09:08:45
Option Public
Option Declare

Sub Initialize
   Dim s As New NotesSession
   Dim db As NotesDatabase
   Dim view As NotesView
   Dim doc As NotesDocument
   Dim vc As NotesViewEntryCollection *
   Dim str_datum, str_aktdatum, str_raumname As String **
   Dim col As NotesDocumentCollection *
   Dim arg As String, p1 As Long
   Dim argarray As Variant
   Dim todaysdate As New NotesDateTime("Today")
   Dim startdatum, enddatum, raumname As String **
   Dim teilnehmer As String
   Dim besprechtitel As String

* nicht verwendete Variablen solltest Du nicht definieren
** diese Deklarationen sind m.W. nicht korrekt, da die ersten Variablen Variants werden, und keine Strings

   str_aktdatum = todaysdate.DateOnly

   On Error GoTo processError

   arg = s.DocumentContext.Query_String(0)
   p1 = InStr(arg, "&")
   arg = LCase(Mid$(arg, p1 + 1))                     ' alle Parameter aus der URL extrahieren
   argarray = Evaluate({@Explode("} & arg & {"; "&")})      ' jeden Parameter trennen und in Array speichern

   Hier könntest Du auch den Script-Befehl Split verwenden

   str_datum = argarray(0)
   str_raumname = argarray(1)
   Du solltest vorher prüfen, ob es argarray (1) gibt (z.B. If Ubound (argarray) > 0 Then ...)
   If str_datum = "" Then                           ' Wenn kein Datum angegeben wurde, dann aktuelles Datum wählen
      str_datum = str_aktdatum
   End if
 
   Set db = s.GetDatabase("MAILSERVER/SRV/Group", "Besprech.nsf", False)
Server- und Dateinamen solltest Du nicht hart codieren, und wenn Du keine Möglichkeit siehst, diese Information irgendwo zu hinterlegen oder automatisch zu ermitteln (z.B. den Server aus der aktuellen Datenbank), dann sollte die Definition in Konstanten ganz oben im Script erfolgen, damit Du die später schnell findest und ändern kannst
Const server = "Mailserver/...."
   If Not db.IsOpen Then Call db.Open("", "")

   Set view = db.GetView("Reservierungen nach Datum")         ' Alle Reservierungen nach Datum
   Set doc = view.GetFirstDocument

   While Not(doc Is Nothing)                           ' Alle Dokumente in Ansicht abarbeiten
      startdatum = Left(doc.GetItemValue("StartDate")(0),10)
      enddatum = Left(doc.GetItemValue("EndDate")(0),10)
      raumname = doc.GetItemValue("Room")(0)
      If raumname <> "" then
         raumname = Left(raumname,InStr(raumname,"/")-1)
Das kracht, wenn Raumname kein "/" enthält, sicherer ist
         raumname = Left(raumname,InStr(raumname & "/","/")-1)
      End if
      teilnehmer = doc.GetItemValue("Capacity")(0)
      besprechtitel = doc.GetItemValue("Purpose")(0)
      If str_datum = startdatum Or str_datum = enddatum Then
         If str_raumname = "" Or str_raumname = LCase(raumname) Then
            Print startdatum, enddatum, raumname, teilnehmer, besprechtitel, "<br>"
         End if
      End If
      Set doc = view.GetNextDocument(doc)
   Wend   
   Exit Sub
processError:
   Print "Fehler " & Str(Err) & ": " & Error$ & " in Zeile " & Str(Erl)
   Exit Sub   
End Sub

Deine Suchlogik solltest Du überprüfen. Wenn Du einen Raum hast, der vom 01.12. bis zum 03.12. gebucht ist, und Du suchst nun nach diesem Raum am 02.12., wirst Du ihn so nicht finden, da Du nur Start- und Enddatum vergleichst. Auch das Durchkämmen der ganzen Ansicht wird mit der Dauer immer langsamer werden, wenn alte Einträge stehen bleiben. Ich würde da lieber ein db.Search nehmen. Da könntest Du
1. nur nach dem Raum suchen
2. nach Buchungen, deren Anfangsdatum <= dem Suchdatum ist und deren Enddatum >= dem Suchdatum ist (mehrtägige Buchungen hast Du anscheinend nicht in Deiner Suchabfrage)
Als Ergebnis hast Du gleich alle relevanten Dokumente. Die musst Du dann nur noch sortieren
Titel: Re: Lotusscript Optimierung
Beitrag von: schroederk am 09.11.11 - 09:48:29
Vielen Dank für die Prüfung und die konstruktiven Anmerkungen.
Ich werde sie beherzigen.

Bei den Variablen-Deklarationen verhau ich mich immer wieder, dank anderer Programmiersprachen.

Bei unseren Besprechungen haben wir bisher noch keine Reservierung gehabt, die länger als 1 Tag gedauert hat. Aber sicher hast Du recht, dass hier zukünftige Eventualitäten gleich berücksichtigt werden sollte.

Ich werde mir die Suche mit db.Search mal anschauen. Ist damit sicher besser umgesetzt.
Titel: Re: Lotusscript Optimierung
Beitrag von: mezz am 09.11.11 - 10:01:14
Code
   arg = s.DocumentContext.Query_String(0)
   p1 = InStr(arg, "&")
   arg = LCase(Mid$(arg, p1 + 1))                     ' alle Parameter aus der URL extrahieren
   argarray = Evaluate({@Explode("} & arg & {"; "&")})      ' jeden Parameter trennen und in Array speichern

Dazu noch eine Anmerkung: Dieses oder ähnliche Konstrukte sieht man leider häufiger, der QueryString wird hier ungefiltert in ein Evaluate übernommen dies kann im ungünstigsten Fall dazu führen das in den QueryString eingehängter Code (Formelsprache) im Kontext des Programmes/Agenten ausgeführt wird.
Ich empfehle mal etwas Lektüre zum Thema Sicherheit in Webanwendungen. :)
Titel: Re: Lotusscript Optimierung
Beitrag von: schroederk am 09.11.11 - 10:54:47
Danke für den Hinweis, mezz. Da der Agent nicht vom Benutzer sondern vom Webserver aufgerufen wird, ist da die Manipulationsmöglichkeit eingeschränkt. Zudem habe ich jetzt auf die Split-Funktion umgebaut, insofern konnte ich auf das Evaluate verzichten. (Bin ich eh kein Fan von)

Die Suche mit db.Search bereitet mir noch ein paar Problemchen. Die Hilfe ist dabei etwas verwirrend und die gefundenden Beispiele im Internet halfen nicht wirklich weiter.
In den Beispielen wird immer innerhalb einer Form gesucht. Kann ich anstelle der Form auch nach einer View suchen?

Also etwa sowas:
searchFormula = {View = "Reservierungen nach Datum" & Left(StartDate,10) <= str_datum & Left(EndDate,10) >= str_datum}

Ist die Suche wirklich schneller oder wäre es nur schneller wenn man FTSearch verwendet. (Vorausgesetzt, dass der Fulltext Index erstellt wurde, was ja nicht das Problem darstellen sollte)
Titel: Re: Lotusscript Optimierung
Beitrag von: koehlerbv am 09.11.11 - 10:58:10
Warum sollte man das über eine View machen (was bei dbSearch eh nicht gehen kann)?

Wenn Dir aber die Vorauswahl einer View gefällt, kannst Du die SELECT-Formel der View als Teil Deines dbSearch-Querystrings mit einbauen.

Bernhard
Titel: Re: Lotusscript Optimierung
Beitrag von: Peter Klett am 09.11.11 - 12:17:43
searchFormula = {View = "Reservierungen nach Datum" & Left(StartDate,10) <= str_datum & Left(EndDate,10) >= str_datum}

Ein db.Search sucht nur Dokumente. Wenn Du alle Dokumente einer Ansicht haben willst, übernimmst Du die Selektionsformel der Ansicht.

Beispiel:

Du hast eine Ansicht "Reservierungen" mit der Selectionsformel: Form = "reservierung"

Unter Verwendung eines db.Search ({Form = "reservierung"}, Nothing, 0) bekommst Du genau die gleichen Dokumente in die NotesDocumentCollection, die auch in der Ansicht sind.

Verstehe db.Search als eine temporäre Ansicht, die Du zur Laufzeit generierst, nur dass das Ergebnis eben eine NotesDocumentCollection ist, dann ist es ganz einfach, damit zu arbeiten. Du hast dabei den Vorteil, dass Du die Selektionsformel dynamisch errechnen kannst, was in einer Ansicht nicht geht.

Ich arbeite sehr viel mit db.Search und behaupte, dass die Performance nicht wirklich schlecht ist. Dadurch erspare ich mir sehr viele Ansichten, die die Datenbank auch nicht gerade schneller machen würden. Bei Zugriff auf fremde Datenbanken habe ich u.U. auch keine Möglichkeit (oder will es auch nicht), eine benötigte Ansicht einzubauen. Defekte Indizes kenne ich dabei auch nicht.

Wir hatten neulich hier im Forum über db.Search diskutiert, vielleicht findest Du da auch noch ein paar hilfreiche Hinweise.

Nachtrag: In Deiner angegebenen Suchformel vergleichst Du Datum auf Textbasis, das wird nicht klappen

"01.01.2012" ist kleiner als "02.01.2011", aber nur als Text, nicht als Datum
Titel: Re: Lotusscript Optimierung
Beitrag von: schroederk am 09.11.11 - 14:03:57
Von diesen Date-Operationen bekomm ich irgendwie immer Kopfschmerzen  :-\

In str_aktdatum steht "09.11.2011", in StartDate steht bspw. "09.11.2011 08:00:00 CET"

Ich habe den Quellcode jetzt folgendermaßen ergänzt:

Dim comparedate As Variant
Set comparedate = CDat(str_aktdatum)
searchFormula = {Form = "Reservierungen nach Datum" & StartDate <= comparedate & EndDate >= comparedate}

Die Folge ist ein Type Mismatch (wobei die angegeben Zeile bei mir eine Leerzeile ist  ???)

Muss ich erst das "09.11.2011" in ein "11/09/2011" umwandeln, damit CDat funktioniert oder liegt der Fehler jetzt beim Vergleich Startdate <= comparedate?
Titel: Re: Lotusscript Optimierung
Beitrag von: ascabg am 09.11.11 - 14:10:06
Hallo,

Kleine Frage.

Code
Set comparedate = CDat(str_aktdatum)
Warum machst Du hier ein Set?

Es reicht doch comparedate = cdat(str_aktdatum)


Andreas
Titel: Re: Lotusscript Optimierung
Beitrag von: schroederk am 09.11.11 - 14:18:35
Hmm, weil er mir beim Schreiben gemeckert hatte, ich müsste ein 'Set' davorsetzen. Jetzt hab ich es wieder weggenommen, keine Fehlermeldung mehr.
Allerdings auch noch das Problem, dass die searchFormula offenbar keine Elemente findet.
Ich befürchte, ich vergleiche noch immer Äpfel mit Birnen  :-:
Titel: Re: Lotusscript Optimierung
Beitrag von: ascabg am 09.11.11 - 14:23:46
Muesste die searchFormula nicht so aussehen.

searchFormula = {Form = "Reservierungen nach Datum" & StartDate <= } & comparedate & { EndDate >= } & comparedate

comparedate ist doch Deine Variable und kein Feld der betreffenden Form.


Andreas
Titel: Re: Lotusscript Optimierung
Beitrag von: koehlerbv am 09.11.11 - 14:24:21
Gibt es denn überhaupt eine Maske namens "Reservierungen nach Datum"? Das wäre ein schräger Maskenname ...

Bernhard
Titel: Re: Lotusscript Optimierung
Beitrag von: koehlerbv am 09.11.11 - 14:26:51
Muesste die searchFormula nicht so aussehen.

searchFormula = {Form = "Reservierungen nach Datum" & StartDate <= } & comparedate & { EndDate >= } & comparedate

comparedate ist doch Deine Variable und kein Feld der betreffenden Form.


Andreas

Das knallt auch, Andreas - eine DT-Variable kannst Du nicht mit einem String verhereiraten.

Statt comparedate müsste ein Konstrukt wie @Date (....) gebildet werden.

Bernhard
Titel: Re: Lotusscript Optimierung
Beitrag von: Peter Klett am 09.11.11 - 14:38:12
searchFormula = {Form = "Reservierungen nach Datum" & StartDate <= @TextToTime ("} & comparedate & {") &  EndDate >= @TextToTime ("} & comparedate & {")}

wäre eine Möglichkeit, wobei das @TextToTime das Risiko birgt, bei abweichenden Ländereinstellungen falsche Ergebnisse zu liefern. Da wird dann ein @TextToTime ("04.01.2011") plötzlich zum ersten April.

Ganz sauber bekommst Du es hin, wenn Du die Datumsangaben in ein Textformat wie JJJJMMNN umwandelst, das kannst Du dann auch als Text mit <= korrekt vergleichen.

Bist Du sicher, dass die Form "Reservierungen nach Datum" lautet?

Nachtrag: Das hatte Bernhard schon geschrieben, hatte ich nicht gesehen ...
Titel: Re: Lotusscript Optimierung
Beitrag von: koehlerbv am 09.11.11 - 14:44:21
Auch das gibt einen type mismatch, Peter, da "..(" & comparedate nicht zusammen passt.

Andererseits würde es kein Einstellungsproblem geben, da alle Umwandlungen ja in der gleichen Maschine stattfinden.

Bernhard
Titel: Re: Lotusscript Optimierung
Beitrag von: schroederk am 09.11.11 - 14:57:26
Ohne die "Form = ..." funktioniert die Suche jetzt.
Allerdings nicht wesentlich schneller, als die View zu selektieren und alle Dokumente in der Schleife abzuarbeiten.
Die Form muss wohl richtigerweise "Reservations By Date Template" heissen. So zumindest der Alias.
Funktioniert aber auch damit nicht.
Titel: Re: Lotusscript Optimierung
Beitrag von: koehlerbv am 09.11.11 - 15:00:25
Das ist keine Form, sondern eine view! Und nützt Dir somit gar nichts.

Bernhard
Titel: Re: Lotusscript Optimierung
Beitrag von: Thomas Schulte am 09.11.11 - 15:01:57
Das ist ein $$ViewTemplate und keine Form. Die Form ist das was bei so einer Reservierung im Feld Form drinsteht. Deine Selektion kann nicht funktionieren.

(Bernhard war schneller)
Titel: Re: Lotusscript Optimierung
Beitrag von: ascabg am 09.11.11 - 15:09:12
@Bernhard,

Auch wenn die Programmierung dadurch nicht "sauber" wird, warum kann ich die beiden Sachen nicht miteinander verheiraten?
Code
Das knallt auch, Andreas - eine DT-Variable kannst Du nicht mit einem String verhereiraten.

Das folgende Konstrukt funktioniert doch auch problemlos.

Code
Dim varTest  as Variant
Dim strTest as String

varTest = cdat("01.01.2011")
strTest = "Heute ist der " & varTest

Msgbox strTest


Andreas
Titel: Re: Lotusscript Optimierung
Beitrag von: koehlerbv am 09.11.11 - 15:11:30
Füg da mal noch weitere Terme dazu - das muss dann nicht mehr gut gehen mit solcher Ferkelei  ;)

Bernhard
Titel: Re: Lotusscript Optimierung
Beitrag von: Peter Klett am 09.11.11 - 15:15:36
Auch das gibt einen type mismatch, Peter, da "..(" & comparedate nicht zusammen passt.
Das hängt davon ab, welchen Inhalt comparedate hat. Ich habe es so verstanden, dass comparedate ein Variant ist und mit CDat gefüllt wird (so ist es zumindest beschrieben). Und natürlich kann man Text und solch ein Datum mittels & zu einem String zusammenfassen. Type mismatch käme bei Verwendung von +, aber das nutzt ja wohl hoffentlich niemand bei Strings (hier auch schon 1000 mal erwähnt). Und wenn man ganz genau sein will, macht man halt ein Cstr () darum ...

Andererseits würde es kein Einstellungsproblem geben, da alle Umwandlungen ja in der gleichen Maschine stattfinden.
Da wäre ich mir nicht sicher, das Datum wird als Parameter einer URL mitgegeben. Erfolgt da die Bearbeitung nicht auf dem Server? Ich gehe mal davon aus, dass der User nicht mit seinem Browser direkt auf dem Server sitzt ...
Titel: Re: Lotusscript Optimierung
Beitrag von: koehlerbv am 09.11.11 - 15:23:59
Sorry, das mit dem Browser habe ich aus den Augen verloren.

Was comparedate angeht: In @Date (YYYY; MM; DD) umwandeln und es passt.

Bernhard
Titel: Re: Lotusscript Optimierung
Beitrag von: schroederk am 09.11.11 - 15:28:26
Da war ich wohl der irrigen Annahme, dass ich im Designer unter Forms auch nur Forms finde und keine Views.
Daher vielen Dank Thomas, somit weiß ich jetzt, wie ich zukünftig herausfinde, welche Form ich verwenden kann.

Einen wesentlichen Einfluss auf die Geschwindigkeit hatte es aber jetzt auch nicht mehr.

Da werde ich mir jetzt mal FTSearch anschauen...

Zum Thema Sicherheit:
Hintergrund ist, dass eine Mitarbeiterin ein "dummes" Terminal vorgesetzt bekommen soll, in dem schlicht die für den aktuellen Tag eingetragenen Besprechungen angezeigt werden, für die sie verantwortlich ist. Das System wird nicht mal eine Tastatur erhalten und da der Aufruf der Seite mittels PHP und Curl erfolgt, wird auch die URL nicht angezeigt.