使用级联删除包在RavenDB中实现级联功能

3

我有一个基于Raven的应用程序,并正在尝试实现级联删除Bundle。安装似乎非常简单,但是从他们关于级联的1个文档中的映射设置部分对我来说不太清楚。 无论如何,这是我的设置,感谢任何帮助。

// An album class with no reference to photos
class Album
{
    public string Id { get; set; } //ID for album from raven
}

// A photo class with a reference to its parent album
class Photo
{
    public string Id { get; set; } //ID for photo from raven
    public string PhotoName { get; set; }
    public Album PhotoAlbum  { get; set; }
}

// On album store 
session.Store(album);
session.Advanced.GetMetadataFor(album)["Raven-Cascade-Delete-Documents"] =
    RavenJToken.FromObject(new[] { album.Id });

// THIS DOES NOT WORK, But I was assuming that it would search for each document
// with a reference to an album and delete it. 
1个回答

3

首先,在建模文件之间的引用时,您需要引用外部文档的键而不是整个文档。现在您所拥有的会将相册嵌入到文档中。请改为如下操作:

public class Photo
{
    public string Id { get; set; }
    public string PhotoName { get; set; }
    public string AlbumId { get; set; }
}

关于级联删除,该捆绑包只是在删除文档时查看元数据并删除所有引用的文档。它不会帮助您构建那个文档列表。您必须自己完成这项工作。每次添加照片时,您都需要加载相册并将照片的ID添加到相册的级联删除列表中。

因此,在保存相册和前几张照片时:

using (var session = documentStore.OpenSession())
{
    var album = new Album();
    session.Store(album);

    var photoA = new Photo { PhotoName = "A", AlbumId = album.Id };
    var photoB = new Photo { PhotoName = "B", AlbumId = album.Id };
    var photoC = new Photo { PhotoName = "C", AlbumId = album.Id };
    session.Store(photoA);
    session.Store(photoB);
    session.Store(photoC);

    session.Advanced.AddCascadeDeleteReference(album,
                                               photoA.Id,
                                               photoB.Id,
                                               photoC.Id);

    session.SaveChanges();
}

稍后,向现有相册添加照片。
using (var session = documentStore.OpenSession())
{
    // you would know this already at this stage
    const string albumId = "albums/1";

    var photoD = new Photo { PhotoName = "D", AlbumId = albumId };
    session.Store(photoD);

    var album = session.Load<Album>(albumId);
    session.Advanced.AddCascadeDeleteReference(album, photoD.Id);

    session.SaveChanges();
}

这里是我上面使用的AddCascadeDeleteReference扩展方法。你可以自己操作,但这会让事情变得更加简单。将其放入一个静态类中即可。

public static void AddCascadeDeleteReference(
  this IAdvancedDocumentSessionOperations session,
  object entity, params string[] documentKeys)
{
    var metadata = session.GetMetadataFor(entity);
    if (metadata == null)
      throw new InvalidOperationException(
        "The entity must be tracked in the session before calling this method.");

    if (documentKeys.Length == 0)
      throw new ArgumentException(
        "At least one document key must be specified.");

    const string metadataKey = "Raven-Cascade-Delete-Documents";

    RavenJToken token;
    if (!metadata.TryGetValue(metadataKey, out token))
        token = new RavenJArray();

    var list = (RavenJArray) token;
    foreach (var documentKey in documentKeys.Where(key => !list.Contains(key)))
        list.Add(documentKey);

    metadata[metadataKey] = list;
}

我也将该扩展方法添加到Raven.Contrib项目,以备后用。 - Matt Johnson-Pint
当我创建一个照片文档时,元数据在SaveChanges()上就无法保存。 - user516883
如果你正在使用我给你的扩展方法,它会在列表不存在时为你创建它。你使用的是哪个版本?我已经在1.0.992和2.0.2190上测试过了,都可以工作。对元数据的更改确实会在保存更改时被捕获到。 - Matt Johnson-Pint
另外,你在保存更改后是否正确处理了会话?它应该在 using 块中。 - Matt Johnson-Pint
是的,我正在使用“using”块正确处理会话。而且我正在使用第二个版本。我不是说你的方法不正确,因为我已经通过调试确认它确实添加了,但当保存到服务器时却没有任何反应。 - user516883
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接