Как я могу добавить значение в коллекцию, только если значение еще не существует? - PullRequest
0 голосов
/ 03 марта 2019

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

public class MyData
{
    public string Id { get; set; }
    public List<string> Urls { get; set; }
}

Предположим, что все эти три операции происходят асинхронно:

AddValue("foo");
AddValue("bar");
AddValue("foo");

Я смотрел на Patch, но я не вижу, какдобавить в условии.Может ли кто-нибудь показать мне пример того, как я могу это сделать?

Обновление

Вот то, что я сейчас использую

var listing = _session.Query<ListingData>()
    .Where(l => l.ListingId == listingId && l.OwnerId == userId)
    .ToList().SingleOrDefault();

if (listing == null)
    return DataResult.NotFound;

_session.Advanced.Patch(
    listing,
    l => l.PhotoUrls,
    urls => urls.Add(url));

_session.SaveChanges();

Этокажется, работает сейчас, если все идет отлично, но если бы были случаи, например, была бы повторная попытка на стороне приложения, основанная на ложном отрицании, то я думаю, что я бы в конечном итоге с дубликатами, потому что

  • Для получения сущности / идентификатора мне нужно совершить поездку туда и обратно
  • Операция просто добавляет значение, не проверяя, существует ли оно сначала

1 Ответ

0 голосов
/ 03 марта 2019

Просто используйте скрипт патча.

using (var session = store.OpenSession())
{    
    var listing = _session.Query<ListingData>()
      .Where(l => l.ListingId == listingId && l.OwnerId == userId)
      .ToList().SingleOrDefault();

    session.Advanced.Defer(new PatchCommandData(
       id: listing.ListingId,
       changeVector: null,
       patch: new PatchRequest
       {
          Script = @"
             if (this.PhotoUrls.includes(url))
                   throw ‘Url already exists’;
             this.PhotoUrls.push($newUrl);
          ",
          Values =
          {
              ["newUrl"] = "The Url to add"
          }
       },
       patchIfMissing: null));

    session.SaveChanges();
}

См .:

  1. https://ravendb.net/docs/article-page/4.1/csharp/client-api/operations/patching/single-document#non-typed-session-api

  2. https://github.com/ravendb/book/blob/v4.0/Ch04/Ch04.md#patching-documents-and-concurrent-modifications

...