给定这个文档类:
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public SpecialType? DefaultOffer { get; set; }
public Dictionary<SpecialType, string> Specials { get; set; }
}
public enum SpecialType
{
Something1,
Something2
}
我希望从上述文档中投影的这个视图模型:
public class ProductSummary
{
public string Id { get; set; }
public string Name { get; set; }
public string SpecialOffer { get; set; }
}
我创建了以下索引:
public class ProductSummaries : AbstractIndexCreationTask<Product>
{
public ProductSummaries()
{
Map = products => from p in products
select new { p.Id, p.Name, p.DefaultOffer, p.Specials };
TransformResults = (db, products) =>
from p in products
select new
{
Id = p.Id,
Name = p.Name,
SpecialOffer = p.Specials[p.DefaultOffer.Value]
};
}
}
简单来说,我希望视图模型使用Specials
字典中由当前值指示的任何字符串DefaultOffer
。
以下单元测试失败:
[TestMethod]
public void CanIndexIntoDictionary()
{
using (var documentStore = this.GetDocumentStore())
{
documentStore.ExecuteIndex(new ProductSummaries());
// Store some documents
using (var session = documentStore.OpenSession())
{
session.Store(new Product
{
Id = "products/2",
Name = "B",
Specials = new Dictionary<SpecialType, string>
{
{ SpecialType.Something1, "B1" },
{ SpecialType.Something2, "B2" }
},
DefaultOffer = SpecialType.Something2
});
session.SaveChanges();
}
// Make sure it got persisted correctly
using (var session = documentStore.OpenSession())
{
var b = session.Load<Product>("products/2");
Assert.AreEqual("B2", b.Specials[b.DefaultOffer.Value]); // PASSES
}
// Now query and transform
using (var session = documentStore.OpenSession())
{
var result = session.Query<Product, ProductSummaries>()
.Customize(x => x.WaitForNonStaleResults())
.AsProjection<ProductSummary>()
.ToList();
Assert.AreEqual(1, result.Count);
Assert.AreEqual("B2", result.First().SpecialOffer); // FAILS - actual is NULL
}
}
}
我需要做什么才能通过此测试?
* 更新 *
通过使用马特的建议(在下面的评论中)有一个代表 NONE 的 Enum 值,我们可以修改他的答案并摆脱可为空的枚举。整个模型和索引看起来干净多了。
public enum SpecialType
{
None = 0,
Something1,
Something2
}
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public SpecialType DefaultOffer { get; set; }
public Dictionary<SpecialType, string> Specials { get; set; }
}
public class ProductSummaries : AbstractIndexCreationTask<Product,ProductSummary>
{
public ProductSummaries()
{
Map = products => from p in products
select new { p.Name, SpecialOffer = p.Specials[p.DefaultOffer] };
Store(x => x.SpecialOffer, FieldStorage.Yes);
}
}
有趣的是,这个索引消除了对空值检查等的需要,因为当不是字典中包含的键时,RavenDB 简单地设置SpecialOffer
为空值。(仅当 p.Name 包含在 Map 中时才适用。)p.DefaultOffer
Specials