从RavenDB索引中的集合中检索特定类型的项目总和

时间:2013-04-05 09:52:48

标签: .net mapreduce ravendb

我正在尝试使用类似的类和索引定义创建一个索引,如下所示:

public class Foo
{
    public string Tag { get; set; }
    public List<Bar> Bars { get; set; }
}

public abstract class Bar
{
    public int Weight { get; set; }
}

public class IronBar : Bar { }

public class ChocolateBar : Bar { }

public class TagSummary
{
    public string Tag { get; set; }
    public int Count { get; set; }
    public int TotalChocolateBarWeight { get; set; }
    public int TotalIronBarWeight { get; set; }
}

public class TagSummaryIndex : AbstractIndexCreationTask<Foo, TagSummary>
{
    public TagSummaryIndex()
    {
        Map = foos => from f in foos
                      select new
                      {
                          Tag = f.Tag,
                          Count = 1,
                          TotalChocolateBarWeight = f.Bars.OfType<ChocolateBar>().Sum(x=> x.Weight),
                          TotalIronBarWeight = f.Bars.OfType<IronBar>().Sum(x=> x.Weight)
                      };

        Reduce = results => from r in results
                            group r by r.Tag into g
                            select new
                            {
                                Tag = g.Key,
                                Count = g.Sum(x => x.Count),
                                TotalChocolateBarWeight = g.Sum(x => x.TotalChocolateBarWeight),
                                TotalIronBarWeight = g.Sum(x => x.TotalIronBarWeight)
                            };
    }
}

但是当我尝试创建索引时

IndexCreation.CreateIndexes(this.GetType().Assembly, _documentStore);

它会抛出InvalidOperationException。如果我从.OfType<T>()删除Map部分,那么一切都很好(但不是我想要的)。我尝试使用Where(x => x is ChocolateBar)和其他各种类型的检查选项,但无济于事。

我将如何实现这一目标?

由于

1 个答案:

答案 0 :(得分:2)

你可以做的最简单的事情就是在你的班级中添加一些预先计算小计的属性。

public class Foo
{
    public string Tag { get; set; }
    public List<Bar> Bars { get; set; }
    public int ChocolateBarsWeight
    {
        get
        {
            return Bars.OfType<ChocolateBar>().Sum(x => x.Weight);
        }
    }
    public int IronBarsWeight
    {
        get
        {
            return Bars.OfType<IronBar>().Sum(x => x.Weight);
        }
    }
}

然后在索引图中使用这些值:

TotalChocolateBarWeight = f.ChocolateBarsWeight,
TotalIronBarWeight = f.IronBarsWeight

但是,我倾向于同意.OfType<T>()在这种情况下应该有效,但事实并非如此。原因是每个条形的序列化信息都是json中的$type值。每次存储抽象基类型或接口时都会发生这种情况。例如:

{
    "Tag": "A",
    "Bars": [
        {
            "$type": "YourNameSpace.ChocolateBar, YourNameSpace",
            "Weight": 10
        },
        {
            "$type": "YourNameSpace.IronBar, YourNameSpace",
            "Weight": 1000
        }
    ]
}

Raven应该能够接受并妥善处理.OfType<T>()。我会建议它下一个主要版本。