如何在RavenDB中单次存储关联文档至不同集合并一次性查询?
核心问题概要
是否可以实现以下操作:
- 通过一次RavenDB的
Store/StoreAsync调用,将带有关联关系(Tags)的文档(Article)存储到不同的集合中? - 随后通过一次查询获取父文档(Article)及其关联文档(Tags),无需单独包含/加载Tags?
问题说明
目前在RavenDB中,存储带有关联关系的数据到不同集合的常规方式是分别存储各文档。读取数据时,需要使用Include指定关联文档,再调用Load获取。
我想知道是否有办法简化这一流程,实现Articles和关联Tags的一键存储与查询。
我整理了两种实现思路:一种是期望但无法工作的方案,另一种是可行但繁琐的方案,通过对比便于理解。
示例分为以下步骤:
- POCO类定义
- 数据存储
- 索引定义
- 索引查询
POCO类定义
期望但无法工作的实现
namespace Articles { public class ArticlePersistance { public string Id { get; set; } public string Title { get; set; } public List<TagPersistance> Tags { get; set; } // 这里直接引用TagPersistance } [DearRavenDBStoreToSeparateCollectionPlease] // 该特性不存在 public class TagPersistance { public string Id { get; set; } public string Name { get; set; } } }
可行的实现
namespace Articles { public class ArticlePersistance { public string Id { get; set; } public string Title { get; set; } public List<string> Tags { get; set; } // 这里用字符串存储ID } public class TagPersistance { public string Id { get; set; } public string Name { get; set; } } }
数据存储
期望但无法工作的实现
通过一次StoreAsync调用,将ArticlePersistance和TagPersistance存储到各自集合中。但实际这样会把Article和Tags存入同一个集合。
var tag = new TagPersistance() { Name = "Tag1" }; var article = new ArticlePersistance() { Title = "aaa", Tags = new List<TagPersistance> { tag } // 直接嵌入完整Tag对象 }; await session.StoreAsync(article); // 仅调用一次StoreAsync await session.SaveChangesAsync();
可行的实现
分别存储Article和Tags:
var tag = new TagPersistance() { Name = "Tag1" }; await session.StoreAsync(tag); // 单独存储Tag var article = new ArticlePersistance() { Title = "aaa", Tags = new List<string> { tag.Id } // 仅嵌入Tag的ID }; await session.StoreAsync(article); await session.SaveChangesAsync();
索引定义
期望但无法工作的实现
基于ArticlePersistance创建索引,存储完整的Tag对象:
public class Articles_Test : AbstractIndexCreationTask<ArticlePersistance> { public Articles_Test() { Map = articles => from article in articles let tags = article.Tags.Select(t => LoadDocument<TagPersistance>(t)) // 加载关联的Tags select new { Title = article.Title, Tags = tags // 存储完整的Tag对象 }; } }
可行的实现
仅存储Tag名称而非完整Tag对象的索引:
public class Articles_Test : AbstractIndexCreationTask<ArticlePersistance> { public Articles_Test() { Map = articles => from article in articles let tags = article.Tags.Select(t => LoadDocument<TagPersistance>(t)) // 加载关联的Tags select new { Title = article.Title, Tags = tags.Select(t => t.Name) // 仅存储Tag名称 }; } }
索引查询
期望但无法工作的实现
查询索引并一次性获取包含Tags的Article:
// 此代码无法正常工作 var article = await session .Query<ArticlePersistance, Articles_Test>() .Where(a => a.Title == "aaa") .ToListAsync();
可行的实现
该方案可行但繁琐,需要手动处理Article和Tags的关联:
var article = await session .Query<ArticlePersistance, Articles_Test>() .Where(a => a.Title == "aaa") .Include(t => t.Tags) // 包含关联的Tags .ToListAsync(); // 单独查询Tags var tags = await session.LoadAsync<TagPersistance>(article.SelectMany(a => a.Tags));
内容的提问来源于stack exchange,提问作者Simon Lang
相关产品推荐
相关产品推荐

