Search code examples
asp.net-web-api2odata

automatically expand related entity with OData controller


I have these classes:

    public class Items
    {
    [Key]
    public Guid Id { get; set; }
    public string ItemCode { get; set; }
    public decimal SalesPriceExcl { get; set; }
    public decimal SalesPriceIncl { get; set; }

    public virtual ICollection<ItemPrice> SalesPrices { get; set; }

    public Items()
    {
        SalesPrices = new HashSet<App4Sales_ItemPrice>();
    }
}

 public class ItemPrice
{
    [Key, Column(Order = 0), ForeignKey("Items")]
    public Guid Id { get; set; }
    public virtual Items Items { get; set; }

    [Key, Column(Order=1)]
    public Guid PriceList { get; set; }        
    public decimal PriceExcl { get; set; }
    public decimal PriceIncl { get; set; }
    public decimal VatPercentage { get; set; }        

}

I want to query the Items and automatically get the ItemPrice collection.

I've created an OData V3 controller:

    // GET: odata/Items
    //[Queryable]
    public IQueryable<Items> GetItems(ODataQueryOptions opts)
    {
        SelectExpandQueryOption expandOpts = new SelectExpandQueryOption(null, "SalesPrices", opts.Context);
        Request.SetSelectExpandClause(expandOpts.SelectExpandClause);
        return expandOpts.ApplyTo(db.Items.AsQueryable(), new ODataQuerySettings()) as IQueryable<Items>;


    }

But I get the error: "Cannot serialize null feed"

Yes, some Items have no ItemPrice list.

Can I get past this error, or can I do something different?

Kind regards

Jeroen

I found the underlying error is: Unable to cast object of type 'System.Data.Entity.Infrastructure.DbQuery1[System.Web.Http.OData.Query.Expressions.SelectExpandBinder+SelectAllAndExpand1[.Models.Items]]' to type '.Models.Items'.


Solution

  • I've solved it after I came across this post: http://www.jauernig-it.de/intercepting-and-post-processing-odata-queries-on-the-server/

    This is my controller now:

    SelectExpandQueryOption expandOpts = new SelectExpandQueryOption(null, "SalesPrices", opts.Context);
    
            Request.SetSelectExpandClause(expandOpts.SelectExpandClause);
    
            var result = expandOpts.ApplyTo(db.Items.AsQueryable(), new ODataQuerySettings());
            var resultList = new List<Items>();
    
            foreach (var item in result)
            {
                if (item is Items)
                {
                    resultList.Add((Items)item);
                }
                else if (item.GetType().Name == "SelectAllAndExpand`1")
                {
                    var entityProperty = item.GetType().GetProperty("Instance");
                    resultList.Add((Items)entityProperty.GetValue(item));
                }
            }
    
    
            return resultList.AsQueryable();
    

    Jeroen