Skip to content

Problem with open type #211

@Robelind

Description

@Robelind

I'm trying to use an open type in my EDM, but I run into a problem when applying queries.

    public class TestData
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Value { get; set; }
    }

    public class Test
    {
        public int Id { get; set; }
        public ICollection<TestData> Data { get; set; }
    }

    public class TestDTO
    {
        [Key]
        public int Id { get; set; }
        public Dictionary<string, object> Properties { get; set; } = new();
    }

    [ApiController]
    [Route("api/[controller]")]
    public class TestsController : ControllerBase
    {
        public async Task<IActionResult> Get(ODataQueryOptions<TestDTO> options)
        {
            IMapper mapper = new Mapper(new MapperConfiguration(x =>
            {
                x.CreateMap<Test, TestDTO>().ForMember(dest => dest.Properties,
                    cfg => cfg.MapFrom(src => src.Data.Select(d => new KeyValuePair<string, object>(d.Name, d.Value))));
            }));
            IEnumerable<Test> entities =
            [
                new Test { Id = 1, Data = [new TestData { Name = "Value", Value = 10 }] },
                new Test { Id = 2, Data = [new TestData { Name = "Value", Value = 100 }] }
            ];

            return(Ok(await entities.AsQueryable().GetQueryAsync(mapper, options)));
        }
    }

If I do e.g. http://localhost:52769/api/Tests?$orderby=Value
it results in the following exception:

System.InvalidCastException: Unable to cast object of type 'Microsoft.OData.UriParser.SingleValueOpenPropertyAccessNode' to type 'Microsoft.OData.UriParser.SingleValuePropertyAccessNode'.
   at AutoMapper.AspNet.OData.LinqExtensions.<GetOrderByCall>g__GetMethodCall|10_0(<>c__DisplayClass10_0&)
   at AutoMapper.AspNet.OData.LinqExtensions.GetOrderByCall(Expression expression, OrderByClause orderByClause, ODataQueryContext context)
   at AutoMapper.AspNet.OData.LinqExtensions.GetQueryableMethod(Expression expression, ODataQueryContext context, OrderByClause orderByClause, Type type, Nullable`1 skip, Nullable`1 top)
   at AutoMapper.AspNet.OData.LinqExtensions.GetOrderByMethod[T](Expression expression, ODataQueryOptions`1 options, ODataSettings oDataSettings)
   at AutoMapper.AspNet.OData.LinqExtensions.GetQueryableExpression[T](ODataQueryOptions`1 options, ODataSettings oDataSettings)
   at AutoMapper.AspNet.OData.QueryableExtensions.GetQueryable[TModel,TData](IQueryable`1 query, IMapper mapper, ODataQueryOptions`1 options, QuerySettings querySettings, Expression`1 filter)
   at AutoMapper.AspNet.OData.QueryableExtensions.GetQueryAsync[TModel,TData](IQueryable`1 query, IMapper mapper, ODataQueryOptions`1 options, QuerySettings querySettings)
   at CompactStore.API.Controllers.TestsController.Get(ODataQueryOptions`1 options) in C:\Users\wlsrlm\source\repos\Compact Store NextGen\CompactStore\API\Controllers\ItemsController - Copy.cs:line 120
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions