17 Stimmen

Caching-Muster in ASP.NET

Ich habe soeben einen Fehler in einem Framework behoben, das ich entwickle. Der Pseudo-Pseudocode sieht wie folgt aus:

myoldObject = new MyObject { someValue = "old value" };
cache.Insert("myObjectKey", myoldObject);
myNewObject = cache.Get("myObjectKey");
myNewObject.someValue = "new value";
if(myObject.someValue != cache.Get("myObjectKey").someValue)
     myObject.SaveToDatabase();

Im Wesentlichen habe ich also ein Objekt aus dem Cache geholt und dann später das ursprüngliche Objekt mit dem zwischengespeicherten Objekt verglichen, um festzustellen, ob ich es in der Datenbank speichern muss, falls es sich geändert hat. Das Problem entstand, weil das ursprüngliche Objekt ein Verweis ist... so dass das Ändern von someValue auch das referenzierte Cache-Objekt änderte, so dass es nie wieder in der Datenbank gespeichert wurde. Ich habe das Problem behoben, indem ich das Objekt aus der zwischengespeicherten Version geklont habe, wodurch der Verweis getrennt wurde und ich das neue Objekt mit dem zwischengespeicherten vergleichen konnte.

Meine Frage ist: Gibt es eine bessere Methode, ein Muster, das Sie empfehlen können? Ich kann nicht die einzige Person sein, die das schon mal gemacht hat :)

27voto

Mark Brackett Punkte 83046

Eine schmutzige Verfolgung ist der normale Weg, um damit umzugehen, denke ich. Etwa so:

class MyObject {
  public string SomeValue { 
     get { return _someValue; }
     set { 
       if (value != SomeValue) {
          IsDirty = true;
          _someValue = value;
       }
  }

  public bool IsDirty {
     get;
     private set;
  }

  void SaveToDatabase() {
     base.SaveToDatabase(); 
     IsDirty = false;
  }
}

myoldObject = new MyObject { someValue = "old value" };
cache.Insert("myObjectKey", myoldObject);
myNewObject = cache.Get("myObjectKey");
myNewObject.someValue = "new value";
if(myNewObject.IsDirty)
   myNewObject.SaveToDatabase();

2voto

Contra Punkte 2726

Eine kleine Verbesserung der Marks-Antwort bei Verwendung von linq:

Bei Verwendung von Linq wird beim Abrufen von Entitäten aus der DB jedes Objekt als IsDirty markiert. Ich habe eine Abhilfe dafür geschaffen, indem ich IsDirty nicht setze, wenn der Wert nicht gesetzt ist; in diesem Fall: wenn null. Für Ints habe ich den Orig-Wert auf -1 gesetzt und dann darauf geprüft. Dies funktioniert jedoch nicht, wenn der gespeicherte Wert mit dem nicht initialisierten Wert (in meinem Beispiel null) identisch ist.

private string _name;
[Column]
public string Name
{
    get { return _name; }
    set
    {
        if (value != _name)
        {
            if (_name != null)
            {
                IsDirty = true;   
            }
            _name = value;
        }
    }
}

Könnte wahrscheinlich weiter verbessert werden, indem IsDirty nach der Initialisierung irgendwie gesetzt wird.

1voto

Craig Walker Punkte 46757

Ich habe ähnliche Dinge getan, aber ich habe das Problem auch durch Klonen gelöst. Der Unterschied ist, dass ich den Cache das Klonen erledigen ließ. Wenn Sie ein Objekt in den Cache legen, klont der Cache das Objekt zuerst und speichert die geklonte Version (so können Sie das ursprüngliche Objekt verändern, ohne den Cache zu vergiften). Wenn man ein Objekt aus dem Cache holt, gibt der Cache einen Klon des Objekts anstelle des gespeicherten Objekts zurück (wiederum, damit der Aufrufer das Objekt verändern kann, ohne das gecachte/kanonische Objekt zu beeinträchtigen).

Ich denke, dass dies durchaus akzeptabel ist, solange die Daten, die Sie speichern/duplizieren, klein sind.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X