Wiki

Clone wiki

User Apps / Tutorials / Persistenzen richtig nutzen

Persistenzen richtig nutzen

Was du hier lernst

  • Was ist eine Persistenz
  • Speichern von Daten in einer Persistenz
  • Auslesen von Daten aus der Persistenz
  • Verändern von Daten in der Persistenz
  • Daten aus der Persistenz löschen
  • Welche Art von Daten können in einer Persistenz gespeichert werden
  • Unterschied zwischen UserPersistence und AppPersistence
  • Best Practices zur Arbeit mit Persistenzen
  • UserPersistenceNumbers - Eine Klasse, die dir hilft
  • Umfangreiches Beispiel

Was ist eine Persistenz

Persistenzen sind...

  • gleichzusetzen mit einer Datenbank (intern wird SQLite genutzt)

  • beständig (persistent) - Die Daten gehen nach einem Neustart nicht verloren

  • Formlos - Es müssen keine Tabellen vorher angelegt werden

  • auf Channel und App begrenzt. Eine App kann weder auf die Persistenz einer anderen im App im gleichen Channel zugreifen, noch auf eine Persistenz der gleichen App in einem anderen Channel. Aber Tochterchannel teilen sich die Persistenz mit ihrem Hauptchannel.

  • vergleichbar mit einem Kontaktbuch

Warum wie ein Kontaktbuch?

Gemeint ist so ein schönes altes Buch, vielleicht gebunden in Leder. Auf den ersten Seiten können wir allgemeine Infos eintragen (App-Persistenz) und auf den hinteren Seiten Infos zu einzelnen Personen (User-Persistenz). Das zu verstehen ist wichtig. Allgemeine Infos zu der App kann man natürlich bei irgendeinem oder bei allen Nutzern speichern und Infos zu einzelnen Nutzern in der App-Persistenz als großes Objekt - Dies ist aber in der Regel die schlechteste Form der Umsetzung.

Regeln und Namensgebungen

  • Daten die einen einzelnen Nutzer betreffen werden in der jeweiligen Nutzerpersistenz gespeichert (z. B.: Anzahl erreichter Punkte)

  • Daten die viele oder alle Nutzer betreffen gehören in die App-Persistenz (z. B.: Preispool)

  • Daten werden in ihrem natürlichen Typ gespeichert. Zahlen speichert man per setNumber, Texte mit setString

  • Objekte, die man von der API bereitgestellt bekommt, speichert man als ihrem Identifier ab. z. B. speichert man Nutzer mit ihrere UserID ab und nicht als ganzes Objekt.

  • Es ist sinnvoll Persistenz-Schlüsseln selbsterklärende Namen zu geben (schlecht: lgct, besser: loginCount).

Unser erster Code

#!javascript
var App = {};
//Wenn ein Nutzer etwas öffentlich schreibt
App.onPublicMessage = function onPublicMessage(publicMessage) {
    var user = publicMessage.getAuthor();


    //wir zählen die Anzahl der öffentlichen Nachrichten des Users hoch - Sollte kein Wert vorhanden sein, wird dieser automatisch erstellt.
    var messageCount = user.getPersistence().addNumber('number_userMessageCount', 1);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');

};
Hey, das ging ja richtig einfach. Doch wenn der Nutzer wissen will, wie oft er bereits öffentlich geschrieben hat, muss er immer etwas öffentlich schreiben dafür. Also fügen wir unserem Code eine Funktion hinzu, um den Wert auszulesen.

/getMessageCount Erweiterung

#!javascript
var App = {};
//Wenn ein Nutzer etwas öffentlich schreibt
App.onPublicMessage = function onPublicMessage(publicMessage) {
    var user = publicMessage.getAuthor();


    //wir zählen die Anzahl der öffentlichen Nachrichten des Users hoch - Sollte kein Wert vorhanden sein, wird dieser automatisch erstellt.
    var messageCount = user.getPersistence().addNumber('number_userMessageCount', 1);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');

};

App.chatCommands = {};
App.chatCommands.getMessageCount = function(user, params, command) {
    //wir holen die Anzahl der Nachrichten und geben 0 als standard Wert an, falls der Nutzer noch keinen Eintrag hat.
    var messageCount = user.getPersistence().getNumber('number_userMessageCount', 0);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');
};
Nun wollen wir dem Nutzer erlauben, seinen Wert auch wieder zu löschen um von vorne zu zählen.

/deleteMessageCount Erweiterung

#!javascript
var App = {};
//Wenn ein Nutzer etwas öffentlich schreibt
App.onPublicMessage = function onPublicMessage(publicMessage) {
    var user = publicMessage.getAuthor();


    //wir zählen die Anzahl der öffentlichen Nachrichten des Users hoch - Sollte kein Wert vorhanden sein, wird dieser automatisch erstellt.
    var messageCount = user.getPersistence().addNumber('number_userMessageCount', 1);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');

};

App.chatCommands = {};
App.chatCommands.getMessageCount = function(user, params, command) {
    //wir holen die Anzahl der Nachrichten und geben 0 als standard Wert an, falls der Nutzer noch keinen Eintrag hat.
    var messageCount = user.getPersistence().getNumber('number_userMessageCount', 0);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');
};

App.chatCommands.deleteMessageCount = function(user, params, command) {
    user.getPersistence().deleteNumber('number_usrMessageCount');
    user.sendPrivateMessage('Die Anzahl deiner öffentlichen Nachrichten wurde zurückgesetzt.');
};
HUCH! Wem ist es aufgefallen? Dieser neue Code wird nicht funktionieren, da der Schlüsselname falsch geschrieben ist. Dies kann immer wieder mal in der Programmierung vorkommen, gerade da IDEs in der Regel keine Strings autovervollständigen. Natürlich kann man das schnell beheben, doch auf Dauer ist es ärgerlich wenn man hunderte Zeilen Quellcode kontrollieren muss um eventuell einen kleinen Schreibfehler zu finden. Dagegen hilft es, die Schlüssel in einem allgemeinen Objekt zu speichern und nur noch diese in der Funktion zu übergeben.

Persistenzschlüssel in einem Objekt speichern

#!javascript
var App = {};
//wir nennen es PKEYS für PersistenceKeys und nutzen Object.freeze um eine Veränderung des Objekts später zu verhindern.
var PKEYS = Object.freeze({
    USER_NUMBER_MESSAGECOUNT: 'number_userMessageCount'
});

//Wenn ein Nutzer etwas öffentlich schreibt
App.onPublicMessage = function onPublicMessage(publicMessage) {
    var user = publicMessage.getAuthor();


    //wir zählen die Anzahl der öffentlichen Nachrichten des Users hoch - Sollte kein Wert vorhanden sein, wird dieser automatisch erstellt.
    var messageCount = user.getPersistence().addNumber(PKEYS.USER_NUMBER_MESSAGECOUNT,1);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');

};

App.chatCommands = {};
App.chatCommands.getMessageCount = function(user, params, command) {
    //wir holen die Anzahl der Nachrichten und geben 0 als standard Wert an, falls der Nutzer noch keinen Eintrag hat.
    var messageCount = user.getPersistence().getNumber(PKEYS.USER_NUMBER_MESSAGECOUNT, 0);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');
};

App.chatCommands.deleteMessageCount = function(user, params, command) {
    user.getPersistence().deleteNumber(PKEYS.USER_NUMBER_MESSAGECOUNT);
    user.sendPrivateMessage('Die Anzahl deiner öffentlichen Nachrichten wurde zurückgesetzt.');
};
Zur Namensgebung. Es macht Sinn direkt am Anfang anzugeben ob es eine UserPersistence Key ist oder doch ein AppPersistence Key. Daher am Anfang das USER_ Dann macht es immernoch Sinn anzugeben, ob es ein Zahlenwert oder ein Text ist. Daher das NUMBER_ Das was sich viele fragen werden - Warum wird alles groß geschrieben. Es ist natürlich frei zu entscheiden, ob man es groß oder klein schreibt, doch in der Programmierung nahezu aller Sprachen hat es sich zum guten Stil entwickelt, alle Konstanten groß zu schreiben, um eine Verwechselung zwischen Variablen, Funktionen, Klassen etc zu vermeiden.

Nun wollen wir unseren Code so erweitern, dass AppManager die Anzahl aller öffentlichen Nachrichten auslesen kann. Hierzu können wir die Summen Funktion der UserPersistenzen nutzen.

/adminGetMessageCount

#!javascript
var App = {};
//wir nennen es PKEYS für PersistenceKeys und nutzen Object.freeze um eine Veränderung des Objekts später zu verhindern.
var PKEYS = Object.freeze({
    USER_NUMBER_MESSAGECOUNT: 'number_userMessageCount'
});

//Wenn ein Nutzer etwas öffentlich schreibt
App.onPublicMessage = function onPublicMessage(publicMessage) {
    var user = publicMessage.getAuthor();


    //wir zählen die Anzahl der öffentlichen Nachrichten des Users hoch - Sollte kein Wert vorhanden sein, wird dieser automatisch erstellt.
    var messageCount = user.getPersistence().addNumber(PKEYS.USER_NUMBER_MESSAGECOUNT,1);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');

};

App.chatCommands = {};
App.chatCommands.getMessageCount = function(user, params, command) {
    //wir holen die Anzahl der Nachrichten und geben 0 als standard Wert an, falls der Nutzer noch keinen Eintrag hat.
    var messageCount = user.getPersistence().getNumber(PKEYS.USER_NUMBER_MESSAGECOUNT, 0);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');
};

App.chatCommands.deleteMessageCount = function(user, params, command) {
    user.getPersistence().deleteNumber(PKEYS.USER_NUMBER_MESSAGECOUNT);
    user.sendPrivateMessage('Die Anzahl deiner öffentlichen Nachrichten wurde zurückgesetzt.');
};

App.chatCommands.adminGetMessageCount = function(user, params, command) {
    //Nur Appmanager dürfen diese Funktion nutzen
    if(!user.isAppManager()) {
        user.sendPrivateMessage('Du darfst diese Funktion nicht nutzen.');
        return; //hier springen wir aus der Funktion raus - Kein Else-Zweig mehr notwendig
    }

    //zählt die Werte aller Nutzer hinzu
    var messageCount = UserPersistenceNumbers.getSum(PKEYS.USER_NUMBER_MESSAGECOUNT);
    user.sendPrivateMessage('Insgesamt haben alle Nutzer ' + messageCount + ' öffentliche Nachrichten geschrieben.');
}
Joa, das ging einfach. Doch ist der Wert nun natürlich nicht korrekt für den AppManager, da die Nutzer ja ihre Werte zurücksetzen können. Was nun? Wir können entweder den echten Wert zusätzlich bei den Nutzern speichern und auf diesen zurückgreifen, oder wir können die AppPersistenz nutzen und hier ebenfalls hochzählen. Vorteil User Persistenz: Wir können zu dem Nutzer ebenfalls immer den echten Wert anzeigen. Vorteil App Persistenz: Es entfällt das Zusammenrechnen aller Werte der User, was minimal schneller ist. Im normalfall würde ich mich für die User Persistenz entscheiden, da dies in Hinblick auf spätere Erweiterungen besser wäre. Aber hier entscheide ich mich mal für die App Persistenz.

Echter Wert für /adminGetMessageCount

#!javascript
var App = {};
//wir nennen es PKEYS für PersistenceKeys und nutzen Object.freeze um eine Veränderung des Objekts später zu verhindern.
var PKEYS = Object.freeze({
    USER_NUMBER_MESSAGECOUNT: 'number_userMessageCount',
    APP_NUMBER_MESSAGECOUNT:  'number_appMessageCount'
});

//wir speichern die Persistenz zwischen um sie nicht immer wieder neu zu holen
App.persistence = KnuddelsServer.getPersistence();

//Wenn ein Nutzer etwas öffentlich schreibt
App.onPublicMessage = function onPublicMessage(publicMessage) {
    var user = publicMessage.getAuthor();


    //wir zählen die Anzahl der öffentlichen Nachrichten des Users hoch - Sollte kein Wert vorhanden sein, wird dieser automatisch erstellt.
    var messageCount = user.getPersistence().addNumber(PKEYS.USER_NUMBER_MESSAGECOUNT,1);

    //wir zählen den Wert in der App nun auch hoch    
    App.persistence.addNumber(PKEYS.APP_NUMBER_MESSAGECOUNT, 1);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');

};

App.chatCommands = {};
App.chatCommands.getMessageCount = function(user, params, command) {
    //wir holen die Anzahl der Nachrichten und geben 0 als standard Wert an, falls der Nutzer noch keinen Eintrag hat.
    var messageCount = user.getPersistence().getNumber(PKEYS.USER_NUMBER_MESSAGECOUNT, 0);

    //wir sagen dem Nutzer wieviel er auch öffentlich geschrieben hat
    user.sendPrivateMessage('Du hast bereits ' + messageCount + ' öffentliche Nachrichten geschrieben.');
};

App.chatCommands.deleteMessageCount = function(user, params, command) {
    user.getPersistence().deleteNumber(PKEYS.USER_NUMBER_MESSAGECOUNT);
    user.sendPrivateMessage('Die Anzahl deiner öffentlichen Nachrichten wurde zurückgesetzt.');
};

App.chatCommands.adminGetMessageCount = function(user, params, command) {
    //Nur Appmanager dürfen diese Funktion nutzen
    if(!user.isAppManager()) {
        user.sendPrivateMessage('Du darfst diese Funktion nicht nutzen.');
        return; //hier springen wir aus der Funktion raus - Kein Else-Zweig mehr notwendig
    }

    //zählt die Werte aller Nutzer hinzu
    var messageCount = App.persistence.getNumber(PKEYS.APP_NUMBER_MESSAGECOUNT);
    user.sendPrivateMessage('Insgesamt haben alle Nutzer ' + messageCount + ' öffentliche Nachrichten geschrieben.');
};

Updated