2
votes

Automapper projection with OData is working just fine, as expected, but if I derive a class from a DTO, it causes the following error:

"exceptionMessage": "The 'TypeIs' expression with an input of type 'EmployeeDTO' and a check of type 'DeveloperDTO' is not supported. Only entity types and complex types are supported in LINQ to Entities queries.",
"exceptionType": "System.NotSupportedException",

The ironic thing is that the derived class is not the one being used in the projection nor is it even mapped.

To better understand the problem, I was able to simplify the problem using the Northwind database. Here is the code:

public class EmployeeDTO
{
    public int EmployeeID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
}

public class DeveloperDTO : EmployeeDTO
{
}

public class EmployeesController : ApiController
{
    [HttpGet]
    [EnableQuery(AllowedQueryOptions = AllowedQueryOptions.Select)]
    public IHttpActionResult Get()
    {
        Mapper.CreateMap<Employee, EmployeeDTO>();

        var dbContext = new NORTHWNDEntities();
        var models = dbContext.Employees;

        var dtos = models.Project().To<EmployeeDTO>();
        return Ok(dtos);
    }
}

Calling this controller with this OData call is what causes the error:

http://<hostname>/api/employees/get?$select=LastName

This only occurs when using the OData select function. The others I tried (skip, top, orderby) all work with no problems.

Now here comes the fun part. Simply commenting out the base class (EmployeeDTO) of the DeveloperDTO class definition and the OData select function works just fine. As you can see, nothing is even utilizing the DeveloperDTO class. It is not mapped, absolutely no uses in the entire project.

This is with Visual Studio 2013, .NET4.5, Wep API 2.2, Automapper 3.3.1, and Microsoft ASP.NET Web API 2.2 for OData 4.0 v5.4.

Recreate the problem:

  1. Create new Web API 2 application.
  2. Add new item of "ADO.NET Entity Data Model" and choose "EF Designer from database". Select "Northwind" database and only choose "Employees" table (Northwind is not Entity Framework friendly).
  3. With Nuget add "Automapper" and "Microsoft ASP.NET Web API 2.2 for OData 4.0"
  4. Add new item "WEb API 2 Controller - Empty" and call it "EmployeesController". Replace the default class with the code listed above. Do not forget to include the two DTO classes.

Run that application with the URL posted above and you will get the error. Comment out the DeveloperDTO class and you will not get the error.

Band-aid fix: If I do not derive any class from the DTO and duplicate all of the members in all classes that would have derived from the DTO, then everything works as expected. However for maintenance sake I would much rather use inheritance.

I delved into the MS Odata code but that gets hairy fast, very hard to follow the flow and I could not figure out the lambda that it was applying to the queryable in order to try and recreate the problem without the "magic" of Web API and the OData decoration.

I have found many posts on SO about Automapper projection and OData in regards to composite DTOs but none that look that it could apply to this case.

Any assistance would be appreciated. Thank you sincerely!

1

1 Answers

0
votes

I have struggled with this problem for hours and blamed OData.

First of all, i found the solution in here Solution is calling Ignore method in model builder.

In your case, when configuring odata with builder, add

builder.Ignore<DeveloperDTO>(); //or whatever you don't want to map.

ODataConventionModelBuilder traverses all models it finds. And somehow OData tries to query base class as derived class then boom??(I think).

Also found documentation of model builders. http://odata.github.io/WebApi/#02-04-convention-model-builder which might be usefull.