OData / OData/AspNetCoreOData

$Count is not working with .NET Core and ODataQueryOptions

Open
#247 29 comments 7 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C#
Stars
505
Forks
186
PR merge metrics
No merged PRs in 30d

Description

I am using Odata with .NET 5.0. Odata version is : (Microsoft.AspNetCore.OData\8.0.1)

$Count is not working in my each request.

http://localhost:33451/odata/Users?$count=true
http://localhost:33451/odata/Users?$skip=20&$top=10&$count=true
http://localhost:33451/odata/Users?$filter=Salary gt 20000 and Salary le 50000&$count=true
http://localhost:33451/odata/Users?$skip=20&$top=10&$filter=Salary gt 20000 and Salary le 50000&$count=true

I am using ODataQueryOptions without EnableQuery.

I also gone through to remove "ApiController" and [Route("[controller]")] but it was not working.

OData Count Issue.zip

using Comman.TestData;
using Domain;
using Domain.BO;
using Domain.Service;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using System;
using System.Collections.Generic;
using System.Linq;
using AspNetCoreOData.Helper;

namespace AspNetCoreOData.Controllers
{
    // [ApiController]
    // [Route("[controller]")]
    public class UsersController : ControllerBase
    {
        private readonly IMapperSession session;

        // 0. Decalare constant - 2000
        private const int batchSize = 2000;

        public UsersController(IMapperSession session)
        {
            this.session = session;
        }

        [HttpGet]
        // [EnableQuery()]
        public IQueryable<User> Get(ODataQueryOptions options)
        {
            // 1. Get all IQuerable<User> from dao. 
            var userList = session.Users;

            // 2. Define Include/ExcludeIDs more than 5000
            List<int> includeIdsList = TestData.GetIncludeExcludeIdList();

            IQueryable<User> results = Enumerable.Empty<User>().AsQueryable();

            for (int i = 0; i < includeIdsList.Count; i = i + batchSize)
            {
                // 3. Split Include/ ExcludeIds in batch(constant - options.count)
                var items = includeIdsList.Skip(i).Take(batchSize).ToArray();

                IQueryable<User> getGridData = IQuerableHelper.GetGridData(userList, items, null);

                if (options.Filter != null)
                {
                    // 4.Apply Filter with Include / ExcludeIds in loop of batch.count and total includeId/ ExcludeId
                    results = results.Concat((IQueryable<User>)options.Filter.ApplyTo(getGridData, new ODataQuerySettings()));
                }
                else
                {
                    results = results.Concat(getGridData);
                }
            }

            if (options.OrderBy != null)
            {
                results = options.OrderBy.ApplyTo(results);  //perform sort 
            }

            if (options.Skip != null)
            {
                results = options.Skip.ApplyTo(results, new ODataQuerySettings());  //perform skip 
            }

            if (options.Top != null)
            {
                results = options.Top.ApplyTo(results, new ODataQuerySettings());  //perform take 
            }

            return results;
        }
    }
}


 public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var connStr = Configuration.GetConnectionString("DefaultConnection");

            services.AddNHibernate(connStr);

            //services.AddControllers()
            //    .AddOData(
            //     opt => opt.Select()
            //    .SkipToken()
            //    .SetMaxTop(100)
            //    .Count()
            //    .Filter()
            //    .AddRouteComponents("odata", GetEdmModel()));


            services.AddControllers().AddOData(opt => opt.Select().Expand().Filter().OrderBy().SetMaxTop(null).SkipToken().Count().AddRouteComponents("odata", GetEdmModel()));

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "AspNetCoreOData", Version = "v1" });
            });

            // services.AddControllersWithViews();

        }

        IEdmModel GetEdmModel()
        {
            var odataBuilder = new ODataConventionModelBuilder();

            odataBuilder.EntitySet<User>("Users");

            odataBuilder.EntitySet<User>("Employee");

            odataBuilder.EntitySet<WeatherForecast>(nameof(WeatherForecast));

            return odataBuilder.GetEdmModel();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "AspNetCoreOData v1"));
            }

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();

            });

        }
    }

Request URL :
http://localhost:33451/odata/users?$skip=10&$top=10&$count=true
**Response : **

{
    "@odata.context": "http://localhost:33451/odata/$metadata#Users",
    "value": [
        {
            "UserID": 7238,
            "FirstName": "adam",
            "LastName": "adkins",
            "Designation": "Business Administrator",
            "Email": "adam@datenwerk.com",
            "Mobile": "1342532785",
            "Gender": "Female",
            "Salary": 19144.00,
            "CreatedAt": "2010-07-25T00:00:00+05:30"
        },
        {
            "UserID": 7239,
            "FirstName": "adolph",
            "LastName": "adams",
            "Designation": "Software Developer",
            "Email": "adolph@datenwerk.com",
            "Mobile": "0335938520",
            "Gender": "Male",
            "Salary": 35966.00,
            "CreatedAt": "2010-04-15T00:00:00+05:30"
        },
        {
            "UserID": 7240,
            "FirstName": "Alpesh",
            "LastName": "adkins",
            "Designation": "Frontend Developer",
            "Email": "Alpesh@datenwerk.com",
            "Mobile": "0620974648",
            "Gender": "Female",
            "Salary": 23516.00,
            "CreatedAt": "2012-02-26T00:00:00+05:30"
        },
        {
            "UserID": 7241,
            "FirstName": "abel",
            "LastName": "acosta",
            "Designation": "Technical Lead",
            "Email": "abel@datenwerk.com",
            "Mobile": "0000082508",
            "Gender": "Female",
            "Salary": 36391.00,
            "CreatedAt": "2020-07-24T00:00:00+05:30"
        },
        {
            "UserID": 7242,
            "FirstName": "abe",
            "LastName": "abbott",
            "Designation": "Software Developer",
            "Email": "abe@datenwerk.com",
            "Mobile": "4621393553",
            "Gender": "Male",
            "Salary": 19025.00,
            "CreatedAt": "2018-07-18T00:00:00+05:30"
        },
        {
            "UserID": 7243,
            "FirstName": "abby",
            "LastName": "adams",
            "Designation": "Manager",
            "Email": "abby@datenwerk.com",
            "Mobile": "3370941413",
            "Gender": "Female",
            "Salary": 11530.00,
            "CreatedAt": "2011-02-20T00:00:00+05:30"
        },
        {
            "UserID": 7244,
            "FirstName": "adolfo",
            "LastName": "adams",
            "Designation": "Manager",
            "Email": "adolfo@datenwerk.com",
            "Mobile": "5541084362",
            "Gender": "Female",
            "Salary": 38385.00,
            "CreatedAt": "2015-05-01T00:00:00+05:30"
        },
        {
            "UserID": 7245,
            "FirstName": "Maulik",
            "LastName": "acosta",
            "Designation": "QA",
            "Email": "Maulik@datenwerk.com",
            "Mobile": "0574550885",
            "Gender": "Female",
            "Salary": 10403.00,
            "CreatedAt": "2020-05-01T00:00:00+05:30"
        },
        {
            "UserID": 7246,
            "FirstName": "adam",
            "LastName": "acosta",
            "Designation": "Software Developer",
            "Email": "adam@datenwerk.com",
            "Mobile": "0072052077",
            "Gender": "Male",
            "Salary": 36698.00,
            "CreatedAt": "2015-03-14T00:00:00+05:30"
        },
        {
            "UserID": 7247,
            "FirstName": "Alpesh",
            "LastName": "abbott",
            "Designation": "Technical Lead",
            "Email": "Alpesh@datenwerk.com",
            "Mobile": "7722694832",
            "Gender": "Male",
            "Salary": 10209.00,
            "CreatedAt": "2013-04-20T00:00:00+05:30"
        }
    ]
}

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the request against UsersController.Get in the attached sample and review the OData setup in Startup.ConfigureServices. Trace how ODataQueryOptions are applied for filter, skip, and top, and compare that path with the requested count behavior. Done means the response includes the expected count for the shown requests without breaking the other query options.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.