RavenDB跨实体查询匹配非标识符属性

时间:2013-01-14 16:56:28

标签: c# linq mapreduce ravendb

我在RavenDB中有以下实体集合:

public class EntityA
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string[] Tags { get; set; }
}

public class EntityB
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string[] Tags { get; set; }
}

唯一共享的是Tags集合:EntityA中可能存在EntityB的标记,因此它们可能相交。

如何检索与EntityA交叉标记的每个EntityB,其中Name EntityB属性等于给定值?

1 个答案:

答案 0 :(得分:2)

嗯,这很难。要做到这一点,你需要两个级别的减少 - 一个通过标记来扩展你的结果,另一个通过id来折叠它。 Raven没有一种简单的方法可以做到这一点。

你可以使用Transform来伪造它。唯一的问题是您的结果集中会有skipped items,因此请务必了解how to deal with those

public class TestIndex : AbstractMultiMapIndexCreationTask<TestIndex.Result>
{
    public class Result
    {
        public string[] Ids { get; set; }
        public string Name { get; set; }
        public string Tag { get; set; }
    }

    public TestIndex()
    {
        AddMap<EntityA>(entities => from a in entities
                                    from tag in a.Tags.DefaultIfEmpty("_")
                                    select new
                                        {
                                            Ids = new[] { a.Id },
                                            Name = (string) null,
                                            Tag = tag
                                        });

        AddMap<EntityB>(entities => from b in entities
                                    from tag in b.Tags
                                    select new
                                        {
                                            Ids = new string[0],
                                            b.Name,
                                            Tag = tag
                                        });

        Reduce = results => from result in results
                            group result by result.Tag
                            into g
                            select new
                                {
                                    Ids = g.SelectMany(x => x.Ids),
                                    g.First(x => x.Name != null).Name,
                                    Tag = g.Key
                                };

        TransformResults = (database, results) => 
                           results.SelectMany(x => x.Ids)
                                  .Distinct()
                                  .Select(x => database.Load<EntityA>(x));
    }
}

另请参阅完整单元测试here

还有另一种方法,但我还没有测试过它。那就是使用Indexed Properties Bundle进行第一次传递,然后将这些结果映射到第二次传递。我一般都在尝试这个,如果有效,我会用结果更新这个答案。