5

This question is very similar but does not give me what I need.

I am using Entity Framework 6. My database has two tables, Customers and CustomerTypes. I have created a ViewModel for each. A customer can have a type:

public class Customer
{
    public int CustomerID { get; set; }
    public string CustomerName { get; set; }
    public CustomerTypeViewModel CustomerType { get; set; }
}

public class CustomerTypeViewModel
{
    public int CustomerTypeID { get; set; }
    public string CustomerTypeDescription { get; set; }
}

I have a Customer controller which exposes an odata action method with a return type of IQueryable:

[HttpPost, Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
    public IQueryable<CustomerViewModel> GetCustomersMatchingCriteria([FromBody]ODataActionParameters parameters)
    {
        var criteria = (CustomerMassUpdateCriteriaViewModel)parameters["Criteria"];

        return Common.Customers.GetCustomerMassUpdateCriteriaResults(criteria,
            ConfigurationManager.AppSettings["CLIENT_ID"]).Select(
            c => new CustomerViewModel()
            {
                CustomerID = c.CustomerID,
                CustomerName = c.CustomerName,
                CustomerType = new CustomerTypeViewModel() 
                {
                    CustomerTypeDescription = c.CustomerType.CustomerTypeDescription
                }
            });
    }

The Common.Customers.GetCustomerMassUpdateCriteriaResults method just returns an IQueryable of Customer, which is the actual entity.

The problem is, when calling this controller method with the following query string options:

$expand=CustomerType
$select=CustomerID,CustomerName,CustomerType/CustomerTypeDescription

This exception is thrown:

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","type":"System.InvalidOperationException"

The argument to DbIsNullExpression must refer to a primitive, enumeration or reference type.

Removing the $expand option and the associated CustomerType/CustomerTypeDescription property from the $select list produces no error.

I feel like I'm missing something obvious, here. Any ideas?

1st EDIT:

Enumerating the results via the ToList() extension method and returning IEnumerable rather than IQueryable successfully expands the CustomerType navigation property, but my ODATA $select list is no longer respected at the database level. Doesn't that defeat the purpose of using ODATA?

Community
  • 1
  • 1
aardvark
  • 328
  • 2
  • 14
  • 1
    Did you end up with a solution for this? I'm still trying to sort this out. – Josh Nov 21 '13 at 01:17
  • @Josh, no, I didn't. What I ended up doing was creating a more-specific viewmodel (or dto or whatever your case may be) for my need. I was needing access to a property of a nested property, and it would be nice to get that working with "$expand", but instead I ended up just sticking that property on my main viewmodel and abandoned both the "$expand" option and the nested property. I had to rethink some things architecturally because of this and I don't really like this solution, but apparently it's the only option I have as of now. – aardvark Nov 25 '13 at 21:33

1 Answers1

0

Exception :

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.","type":"System.InvalidOperationException"

per my knowledge is due to how request is reaching for OData formatting. The request should come to OData route for formatting. If you could move GlobalConfiguration.Configuration.EnableOData() before RouteConfig.RegisterRoutes and WebApiConfig.Register in global.asax could help.

Sumit
  • 136
  • 5
  • From what I understand, the Queryable(AllowedQueryOptions = AllowedQueryOptions.All) attribute should do the same thing at a more local level, but I did attempt to try your suggestion, and found that the EnableOData() method is not a member of GlobalConfiguration.Configuration. Perhaps it's not available in WebAPI 5.0? – aardvark Nov 08 '13 at 15:39