仅在值不存在的情况下,如何才能将其添加到集合中?

时间:2019-03-02 22:57:09

标签: ravendb

在ravendb中,我试图解决一个竞争条件,即可以将多个URL同时添加到单个文档中。为了安全地执行此操作(并且不在集合中创建重复的条目),我需要在数据库上自动进行条件检查和数组推送。例如,结构可能如下所示:

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

假设所有这三个操作都是异步发生的:

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

我当时在查看补丁,但我没有看到如何添加条件。有人可以给我举个例子说明我该怎么做吗?

更新

这是我目前正在使用的

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

如果一切顺利,这似乎暂时可行,但是例如,在某些情况下,将发生基于错误否定的应用程序侧重试,那么我认为我最终会重复,因为

  • 要获取实体/ id,我必须进行一次往返行程
  • 该操作仅添加值,而无需检查是否首先存在

1 个答案:

答案 0 :(得分:2)

只需使用补丁脚本即可。

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