How to use Automapper Queryable extension with OData, nested $select

Viewed 622

I'm trying to implement an API using OData with DTOs using .NET 5.0

[EnableQuery]
public IActionResult Get(ODataQueryOptions<BookDto> options)
{
    ...

    var books = this._db.Books.ProjectTo<BookDto>();

    return Ok(books);
}

Note here, the "options" parameter is there only so I can check the expand statements (which is excluded for brevity), and use explicit expansion, otherwise, I rely on the [EnableQuery] attribute to apply the query.

My EDM model contains the DTOs, instead of the entities, like this:

ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<BookDto>("Books");
builder.EntitySet<PressDto>("Presses");
return builder.GetEdmModel();

The BookDto contains a navigation prop to PressDto:

public class BookDto
{
    public int Id { get; set; }
    ... other props
    public PressDto Press { get; set; }
}
    
public class PressDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Category Category { get; set; }
    public PersonDto Owner { get; set; }
}

This way, the $expands work pretty well, however $select inside expand throws an exception:

  • /odata/books?$expand=Press -> this works fine
  • /odata/books?$expand=Press($expand=Owner) -> this works fine
  • /odata/books?$select=Title -> this works fine

- /odata/books?$expand=Press($select=Category) -> this throws an exception

System.InvalidOperationException: Rewriting child expression from type 'ODataPoc.Models.Category' to type 'System.Nullable`1[ODataPoc.Models.Category]' is not allowed, because it would change the meaning of the operation. If this is intentional, override 'VisitUnary' and change it to allow this rewrite.at System.Linq.Expressions.ExpressionVisitor.ValidateChildType(Type before, Type after, String methodName)at System.Linq.Expressions.ExpressionVisitor.ValidateUnary(UnaryExpression before, UnaryExpression after)at Microsoft.EntityFrameworkCore.Query.Internal.QueryOptimizingExpressionVisitor.VisitUnary(UnaryExpression unaryExpression)

If I use entities instead of DTOs, and no ProjectTo, it works fine. So something is off with the ProjectTo, I just can't figure out what. If possible, I'd like to use DTOs so any help is much appreciated.

0 Answers
Related