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



好的,我有这些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的Product属性可以是它们中的任何一个。

我想定义静态索引,返回每个产品的最低价格的Offers,然后按产品类型过滤它。

我走了这么远。

        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。我,不是全部(我只是不知道怎么做)。

当我查询索引时:

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进行过滤。

通过评论中的讨论,我对这个问题有了更好的理解。具体来说,Product是嵌入在Offer类中的,是其他产品的基类。因此,您不能使用我描述的方法(参见编辑),因为当您索引Offer时,您无法访问Product的元数据。

解决方案是依赖这样一个事实,即您的基类将使用$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));

我在这里把一个完整的单元测试放在一起,向您展示如何使用这种技术来达到您所描述的目标。

最新更新