AutoMapper / AutoMapper.Extensions.OData

Creates LINQ expressions from ODataQueryOptions and executes the query.
MIT License
140 stars 38 forks source link

Support SingleResult #195

Closed lenardchristopher closed 8 months ago

lenardchristopher commented 8 months ago

Source/destination types

Mapping configuration

// Mapper.Initialize or just the CreateMap snippet 

Version: x.y.z

- AutoMapper 12.0.1 - AutoMapper.AspNetCore.OData.EFCore 4.0.1 - Microsoft.AspNetCore.OData 8.2.3 ### Expected behavior

Using ProjectTo, you can use EnableQueryAttribute and SingleResult like this. The docs say for use with [EnableQuery]. However, when using AutoMapper.Extensions.OData, you aren't supposed to use that attribute.

[EnableQuery]
public SingleResult<OrderDTO> GetAsync([FromODataUri] Guid key) =>
    SingleResult.Create(this.context.Orders
        .Where(x => x.OrderId == key)
        .ProjectTo<OrderDTO>(this.mapper.ConfigurationProvider));

I expected to be able to remove EnableQueryAttribute and use GetQueryAsync

public async Task<SingleResult<OrderDTO>> GetAsync(ODataQueryOptions<OrderDTO> options, [FromODataUri] Guid key) =>
      SingleResult.Create(await this.context.Orders
          .Where(x => x.OrderId == key)
          .GetQueryAsync(this.mapper, options));

Actual behavior

I get this error

System.Runtime.Serialization.SerializationException: 'SingleResult`1' cannot be serialized using the OData output formatter.

Steps to reproduce

// Your calls to Mapper.Map or ProjectTo here, with source/destination objects constructed
  1. Setup an endpoint to use SingleResult passing in the awaited IQueryable from GetQueryAsync
BlaiseD commented 8 months ago

Great idea.

BlaiseD commented 8 months ago

What does it buy you though over the following:

        public async Task<OrderDTO> GetAsync(ODataQueryOptions<OrderDTO> options, [FromODataUri] Guid key) =>
          (
            await this.context.Orders
                .Where(x => x.OrderId == key)
                .GetQueryAsync(this.mapper, options)
          )
          .Single();
lenardchristopher commented 8 months ago

@BlaiseD what extension is giving you Single()? I don't see to have that available.

lenardchristopher commented 8 months ago

Nevermind. You are correct. I ended up with something like this

public async Task<ActionResult> GetAsync(ODataQueryOptions<OrderDTO> options, [FromODataUri] Guid key) =>
      this.Ok((await this.context.Orders
          .Where(x => x.OrderId == key)
          .GetQueryAsync(this.mapper, options))
          .Single());

The response format looks good to me. No need for SingleResult.Create. I think this is probably closable unless it's still something you want to address.

BlaiseD commented 8 months ago

Correct - didn't mean to include SingleResult.Create in the previous comment.