Шаблоны кэширования в ASP.NET

Итак, я просто исправил ошибку в рамках, которые я разрабатываю. Псевдо псевдокод выглядит следующим образом:

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();

Итак, по сути, я получал объект из кэша, а затем позже сравнивал исходный объект с кэшированным объектом, чтобы увидеть, нужно ли мне его сохранять в базу данных, если он изменился. Проблема возникла из-за того, что исходный объект является ссылкой... поэтому изменение someValue также изменило ссылочный кешированный объект, поэтому он никогда не будет возвращаться в базу данных. Я исправил его, клонировав объект с кешированной версии, отделив ссылку и позволив мне сравнить новый объект с кешированным.

Мой вопрос: есть лучший способ сделать это, какой-то шаблон, который вы могли бы порекомендовать? Я не могу быть единственным человеком, который сделал это раньше:)

Ответ 1

Грязное отслеживание - это нормальный способ справиться с этим, я думаю. Что-то вроде:

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();

Ответ 2

Я делал схожие вещи, но я обошел его, клонируя тоже. Разница в том, что я сделал кеш клонирования. Когда вы кладете объект в кеш, кеш будет клонировать объект первым и хранить клонированную версию (чтобы вы могли мутировать исходный объект, не отравляя кеш). Когда вы получаете объект из кеша, кеш возвращает клонированный объект вместо хранимого объекта (опять же, чтобы вызывающий объект мог мутировать объект без эффекта кэшированного/канонического объекта).

Я думаю, что это вполне приемлемо, если данные, которые вы храните/дублируете, невелики.

Ответ 3

Небольшое улучшение при использовании Marks anwser при использовании linq:

При использовании Linq выборка объектов из БД будет отмечать каждый объект как IsDirty. Я сделал обходной путь для этого, не устанавливая IsDirty, когда значение не установлено; для этого экземпляра: когда null. Для ints я присваивал значение orig-значение -1, а затем проверял его. Однако это не сработает, если сохраненное значение совпадает с неинициализированным значением (null в моем примере).

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

Может быть, возможно, еще больше улучшится, установив IsDirty после инициализации каким-то образом.