RavenDB Catch 22 - оптимистичный параллелизм и возможность увидеть изменения от других клиентов - PullRequest
2 голосов
/ 30 декабря 2011

С RavenDB, создавая IDocumentSession при запуске приложения (и никогда не закрывая его, пока приложение не будет закрыто), я могу использовать оптимистичный параллелизм, выполняя это:

public class GenericData : DataAccessLayerBase, IGenericData
{
    public void Save<T>(T objectToSave)
    {
        Guid eTag = (Guid)Session.Advanced.GetEtagFor(objectToSave);
        Session.Store(objectToSave, eTag);
        Session.SaveChanges();
    }
}

Если другой пользовательизменил этот объект, тогда сохранение будет некорректно завершено.

Но то, что я не могу сделать, когда при использовании одного сеанса за время жизни приложения наблюдаются изменения, сделанные другими экземплярами приложения (скажем,Джо, пять тв), к документам.Когда я делаю это, я не вижу изменений Джо:

public class CustomVariableGroupData : DataAccessLayerBase, ICustomVariableGroupData
{
    public IEnumerable<CustomVariableGroup> GetAll()
    {
        return Session.Query<CustomVariableGroup>();
    }
}

Примечание: я тоже пробовал это, но он также не отображал изменения Джо:

return Session.Query<CustomVariableGroup>().Customize(x => x.WaitForNonStaleResults());

Теперь, если я пойду другим путем и создам IDocumentSession внутри каждого метода, который обращается к базе данных, у меня возникает противоположная проблема.Поскольку у меня новый сеанс, я вижу изменения Джо.Buuuuuuut ... тогда я теряю оптимистичный параллелизм.Когда я создаю новый сеанс перед сохранением, эта строка создает пустой GUID и, следовательно, дает сбой:

Guid eTag = (Guid)Session.Advanced.GetEtagFor(objectToSave);

Чего мне не хватает?Если сеанс не следует создавать внутри каждого метода или на уровне приложения, то какова правильная область?Как я могу получить преимущества оптимистичного параллелизма и возможности видеть изменения других при выполнении Session.Query ()?

Ответы [ 3 ]

2 голосов
/ 30 декабря 2011

Отказ от ответственности: я знаю, что это не может быть долгосрочным подходом, и поэтому здесь не будет принятого ответа.Тем не менее, мне просто нужно, чтобы что-то работало сейчас, и я могу провести рефакторинг позже.Я также знаю, что некоторые люди будут испытывать отвращение к такому подходу, лол, но пусть будет так.Кажется, это работает.Я получаю новые данные с каждым запросом (новый сеанс), и у меня также работает оптимистичный параллелизм.

Суть в том, что я вернулся к одному сеансу для каждого метода доступа к данным.И всякий раз, когда метод доступа к данным выполняет какой-либо тип get / load / query, я сохраняю электронные теги в статическом словаре:

public IEnumerable<CustomVariableGroup> GetAll()
{
    using (IDocumentSession session = Database.OpenSession())
    {
        IEnumerable<CustomVariableGroup> groups = session.Query<CustomVariableGroup>();
        CacheEtags(groups, session);
        return groups;
    }
}

Затем, когда я сохраняю данные, я беру электронный тег из кэша,Это вызывает исключение параллелизма, если другой экземпляр изменил данные, что я и хочу.

public void Save(EntityBase objectToSave)
{
    if (objectToSave == null) { throw new ArgumentNullException("objectToSave"); }

    Guid eTag = Guid.Empty;

    if (objectToSave.Id != null)
    {
        eTag = RetrieveEtagFromCache(objectToSave);
    }

    using (IDocumentSession session = Database.OpenSession())
    {
        session.Advanced.UseOptimisticConcurrency = true;
        session.Store(objectToSave, eTag);
        session.SaveChanges();
        CacheEtag(objectToSave, session);  // We have a new eTag after saving.
    }
}

Я абсолютно хочу сделать это правильно в долгосрочной перспективе, но я не знаю, что этопуть еще есть.

Редактировать: Я собираюсь сделать это принятым ответом, пока не найду лучший путь.

2 голосов
/ 30 декабря 2011

Вы не увидите изменений, потому что вы используете тот же сеанс.Смотрите мои другие ответы для более подробной информации

1 голос
/ 04 января 2012

Боб, почему бы тебе просто не открывать новую сессию каждый раз, когда ты хочешь обновить свои данные?

У него много компромиссов, позволяющих открывать новые сеансы для каждого запроса, и ваше решение для оптимистичного параллелизма (управления тегами в вашем собственном одноэлементном словаре) показывает, что оно никогда не предназначалось для такого использования.

Вы сказали, что у вас есть приложение WPF. Хорошо, откройте новую сессию при запуске. Загружайте и запрашивайте все, что вы хотите, но не закрывайте сеанс, пока не захотите обновить свои данные (например, список заказов, клиентов, я не знаю ...). Затем, когда вы хотите обновить его (после того, как пользователь нажимает на кнопку, запускается событие таймера или что-то еще), удаляйте сеанс и открывайте новый. Это работает для вас?

...