AspNetCoreOData icon indicating copy to clipboard operation
AspNetCoreOData copied to clipboard

OData Wrapper gets lost on projection

Open audacity76 opened this issue 2 years ago • 3 comments

Assemblies affected ASP.NET Core OData 8.x (latest)

Describe the bug When applying own projection/select to the query the odata wrapper get's lost.

Reproduce steps

        public ActionResult<IQueryable> Get(ODataQueryOptions<ArticleInfo> odata)
        {
            var query = DbContext.ArticleInfos.FromSqlRaw("select 'abc' as Id, 'somevalue' as Value union select 'xyz','othervalue'");

            var newQuery = odata.ApplyTo(query);

            // this line eliminates OData wrapper
            var finalQuery = newQuery.Cast<ArticleInfo>().Select(a => new { a.Value });

            return Ok(finalQuery);
        }

Data Model

public class ArticleInfo
{
    [Key]
    public string Id { get; set; }

    public string Value{ get; set; }
}

EDM (CSDL) Model

<EntityType Name="ArticleInfo">
  <Key>
    <PropertyRef Name="Id"/>
  </Key>
  <Property Name="Id" Type="Edm.String" Nullable="false"/>
  <Property Name="Value" Type="Edm.String"/>
</EntityType>

Request/Response GET Request ArticleInfos?$filter=Id%20eq%20%27abc%27

Response [{"Value":"somevalue"}]

Expected behavior Should be this response: {"@odata.context":"https://localhost:7188/coreservices/odata/$metadata#ArticleInfos(Value)","value":[{"Value":"somevalue"}]}

audacity76 avatar Sep 14 '23 09:09 audacity76

@audacity76

var finalQuery = newQuery.Cast<ArticleInfo>().Select(a => new { a.Value }); it returns an anonymous type that is not defined in the OData model. So, OData output formatter can't be selected based on this anonymous type, it goes to other formatter.

It looks like you want to get partition data, why don't you use '$select=Value' ?

xuzhg avatar Sep 15 '23 18:09 xuzhg

Thanks for your response @xuzhg!

There are other actions involved (which I skipped for simplicity). So, $select is not an option in my case. Any way to get the output formatter running?

audacity76 avatar Sep 15 '23 18:09 audacity76

Some ways at quick glace (no guarantee)

  1. create an intermediate type and use it in Select(a => new YourType { Value = a.Value} ), but it could change the context uri.
  2. manually use "$select=Value" in your controller/action, parse it using ODataQueryOptionParsers (or build the SelectExpandClause manually), build another ODataQueryOption, then, apply to the data.
  3. Customize ODataOutputFormmatter by deriving it and override the 'CanWrite' and other virtual methods.

xuzhg avatar Sep 15 '23 19:09 xuzhg