0
votes

I'm trying to figure out the a way to get extra data to be passed with the entities returned from a RIA domain service.

For example, let's say I want to display a DataGrid for "Orders" and include a column for the total items in an order.

Order Num.  |  Cust. Name |  *No. of Items Ordered*
4545        |  John       |   4    
1234        |  Mike       |   7

On the server side, with a Linq query, I could do:

var query = 
    from o in entities.Orders
    select new OrderWithItemCount { Order = o, ItemCount = o.Items.Count() };

... and this will retrieve my orders along with the Items counts all in one go.

The problem is, I can't find anyway to propagate these results thru a domain service to the Silverlight client. I suppose I could use a standard WCF service, but what's the fun in that?

Update

What turned out to be the actual problem...

I had at one point actually already tried the "Easy way" that Nissan Fan and Florian Lim point out. When I tried it, I wasn't getting all my data. (I also need to include the customer Person in the query to get their name.) It turns out that what I thought was a limitation of RIA Services was actually a limitation of EF 4.0, in that saying entities.Orders.Include("Customer") won't work if you select a new type that isn't an Order. The work around is to explicitly select o.Customer in your select statement, and EF will automatically wire the selected Person into the assiocated property on Order.

2

2 Answers

1
votes

Easy way:

Just add extra fields to your Order class (could be done in a partial class) and populate that in your DomainService.

Complicated but more flexible way:

Define OrderWithItemCount as an entity (needs to have a [Key] attribute), then transfer that.

public class OrderWithItemCount
{
    [Key]
    public int Id { get; set; }

    // You need this, so that the DomainContext on the client can put them back together.
    public int OrderId { get; set; }

    [Include]
    [Association("OrderReference", "OrderId", "Id")]
    public Order Order { get; set; }

    public int ItemCount { get; set; }

    public Person Customer { get; set; }
}

public IQueryable<OrderWithItemCount> GetOrdersWithItemCount()
{
    var query = from o in entities.Orders
                select new OrderWithItemCount
                {
                    OrderId = o.Id,
                    Order = o,
                    ItemCount = o.Items.Count,
                    Customer = o.Customer, // Makes sure EF also includes the Customer association.
                };
    return query;
}

There may be minor errors in the code, since I cannot test this at the moment, but I recently implemented something similar.

1
votes

If you are using LINQ to SQL to produce your Domain Service you could simply go into the partial class for Orders and add a Property called NumberOfOrders which returns an Int representing the count. This property would carry through to the client without issue.

internal sealed class OrderMetadata
        {
// Metadata classes are not meant to be instantiated.
            private OrderMetadata()
            {
            }

            ... (property stubs auto-generated)
        }

        public int NumberOfOrders
        {
            get { return this.Items.Count; }
        }

The reason why you cannot do this the way you demonstrated above is because you cannot marshal across anything but conrete classes (anonyous classes are a no-go). By adding this property to the partial class it will effectively be part of its published signature.