我正在尝试创建一个具有类似类和索引定义的索引,如下所示:
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。如果我从Map
中移除.OfType<T>()
部分,那么一切都很好(但不是我想要的)。我试过使用Where(x => x is ChocolateBar)
和各种其他类型检查选项,但无济于事。
我该怎么做呢?
谢谢
您可以做的最简单的事情可能是在您的类中添加一些预先计算小计的属性。
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>()
。我会在他们的下一个主要版本中推荐它。