如何定义静态索引,处理最小值和多态属性?

时间:2013-01-16 21:18:14

标签: ravendb

好的,我有这些POCO的

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Manufacturer { get; set; }
}

public class Offer
{
    public int Id { get; set; }
    public User Seller { get; set; }
    public Product Product { get; set; }
    public decimal Price { get; set; }
}

我有许多派生自Product的类,而Offer类的产品属性可以是其中任何一个。

我想定义静态索引,以每个产品的最低价格返回商品,然后按产品类型对其进行过滤。

我到目前为止。

        Map = offers => offers.Select(x => new Offer { Product = x.Product, Price = x.Price });

        Reduce = results => from r in results
                            group r by r.Product into g
                            select new Offer { Product = g.Key , Price = g.Min(x => x.Price) };

这确实有效,并且给了我最低的价格,虽然我认为Map应该只使用Product.Id,而不是整个事情(我只是不知道该怎么做)。

当我查询索引时:

Session.Query<Offer>("BestOffersIndex").Where(offer => offer.Product is DerivedProduct)

它只是忽略了Where条件。

如果我这样做:

        Map = offers => offers.Select(x => new OfferIndexResult { ProductType = MetadataFor(x.Product)["Raven-Entity-Name"].ToString(), ProductId = x.Product.Id, Price = x.Price });

        Reduce = results => from r in results
                            group r by r.ProductId into g
                            select new OfferIndexResult { ProductType = g.FirstOrDefault().ProductType, ProductId = g.Key, Price = g.Min(x => x.Price) };

        TransformResults = (database, offers) => from offer in offers
                                                 let product = database.Load<Product>(offer.ProductId.ToString())
                                                 select new Offer { Product = product, Price = offer.Price }; 

实时投影中的已加载产品为空,我不知道如何使用ProductType进行过滤。

感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

根据评论中的讨论,我对问题有了更好的理解。具体来说,Product类中的Offer embedded ,它是其他产品的基类。因此,您无法使用我所描述的方法(请参阅编辑),因为在索引Product时,您无法访问Offer的元数据。

解决方案是依赖于您的基类将使用$type属性进行序列化的事实。这是由Json.Net完成的,因为您正在存储一个派生类型的类。序列化的Offer文档如下所示:

{
  "SellerUserId": 1,
  "Product": {
    "$type": "YourNamespace.TheProductType, YourAssembly",
    "Id": 1,
    "Name": "product name",
    "Manufacturer": "manufacturer"
  },
  "Price": 10.0
}

要绝对确保$type始终存在,请将Product类标记为abstract,以便所有实际产品都必须是派生类。

因此,在构建索引映射时,您需要访问此字段。您可以使用AsDocument方法获取它:

Map = offers => from offer in offers
                select new
                {
                    Product = offer.Product,
                    offer.Price,
                    ProductType = AsDocument(offer.Product)["$type"]
                };

当您进行查询并希望按产品类型进行过滤时,您可以获得如下字符串产品类型:

var productType = documentStore.Conventions.GetClrTypeName(typeof(ProductA));

我已将完整的单元测试here放在一起,向您展示如何使用此技术达到您描述的目标。