Question

I am using RavenDb in C# web project. I have an object that I need to query its child collection with 1 row per child object and some of the root/parent object properties.
Note: This is not the actual design, just simplified for this question.

    public class OrderLine
    {
        public string ProductName { get; set; }
        public int Quantity { get; set; }
        public DateTime? ShipDate { get; set; }
    }
    public class Order
    {
        public int OrderId { get; set; }
        public string CustomerName { get; set; }
        public DateTime OrderDate { get; set; }
        public List<OrderLine> OrderLines { get; set; }

    }

The order with the orderlines is one single document. ShipDate will be updated on each line because not all products are always in stock.

I need to be able to create a list of the last 10 products sent with the following columns:

OrderId
Customer
ProductName
ShipDate

This doesn't work because SelectMany is not supported:

        var query = from helper in RavenSession.Query<Order>()
                        .SelectMany(l => l.OrderLines, (order, orderline) => 
                            new { order, orderline })
                    select new 
                    {
                        helper.order.OrderId,
                        helper.order.CustomerName,
                        helper.orderline.ProductName,
                        helper.orderline.ShipDate

                    };
        var result = query.Where(x => x.ShipDate.HasValue)
            .OrderByDescending(x => x.ShipDate.Value).Take(10);

I believe the right thing to do isto create an Index that will flatten out the list but I haven't had any success. I don't believe a Map-Reduce situation will work because as I understand it will effectively does a group by which Reduces the number of documents to less rows (in the index). But in this case, I am trying to expand the number of documents to more rows (in the index).

I would rather not put each OrderLine in a separate document but I do not know what my options are.

Était-ce utile?

La solution

Since you want to filter and sort by fields in the subclass, you'll need to make sure all the fields you want are indexed and stored.

public class ShippedItemsIndex
    : AbstractIndexCreationTask<Order, ShippedItemsIndex.Result>
{
    public class Result
    {
        public int OrderId { get; set; }
        public string CustomerName { get; set; }
        public string ProductName { get; set; }
        public int Quantity { get; set; }
        public DateTime ShipDate { get; set; }
    }

    public ShippedItemsIndex()
    {
        Map = orders => 
            from order in orders
            from line in order.OrderLines
            where line.ShipDate != null
            select new
            {
                order.OrderId,
                order.CustomerName,
                line.ProductName,
                line.Quantity,
                line.ShipDate
            };

        StoreAllFields(FieldStorage.Yes);
    }
}

Then you can project from the index into your results.

var query = session.Query<Order, ShippedItemsIndex>()
    .ProjectFromIndexFieldsInto<ShippedItemsIndex.Result>()
    .OrderByDescending(x => x.ShipDate)
    .Take(10);

var results = query.ToList();

Here is a complete test demonstrating.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top