OData / OData/AspNetCoreOData

$count is not working correctly with $expand and EF Core HasQueryFilter

Open
#676 22 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Hi,

My situation may be rare topic. I did not find anything about that. I try to tell with a sample.

// These are my entities
public class Customer
{
  public int Id { get; set; }
  public string Name { get; set; }
  public int Age { get; set; }
  public bool IsDeleted { get; set; }

  public List<Activity> Activities { get; set; }
}

public class Activity
{
  public int Id { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }
  
  public int CustomerId { get; set; }
  public Customer Customer { get; set; }
}

public class MyDbContext : DbContext
{
  public DbSet<Customer> Customers { get; set; }
  public DbSet<Activity> Activities { get; set; }

  protected override void OnModelCreating(ModeBuilder builder)
  {
    modelBuilder.Entity<Activity>(e => {
      e.HasOne(a => a.Customer)
        .WithMany(c => c.Activities)
        .HasForeignKey(a => a.CustomerId);
    });

    // Made other property configurations....

    /****** THIS POINT IS IMPORTANT ******/
    modelBuilder.Entity<Customer>().HasQueryFilter(c => !c.IsDeleted);
  }
}

And consider records of the tables in database like the below

Customer

Id Name Age IsDeleted
1 Hakan 32 false
2 John 22 false
3 Jane 54 true
4 Chris 26 false

Activity

Id Name Description CustomerId
1 October Fest bla bla bla... 2
2 Rio Carnaval bla bla bla... 3
3 Christmas bla bla bla... 1
4 Easter bla bla bla... 1

I configured everything well. The web application perfectly run with odata. But some conditions return wrong value.

Let's tell you that,

I called the below query to show on a list.

http://localhost:5000/odata/activity?$expand=customer($select=name)&$select=id,name&$top=10&$count=true

Response to the request is the below:

{
  "@odata.context":"http://localhost:5000/odata/$metadata#Activity(id,name,customer(name))",
  "@odata.count":4,
  "value":[
    {
      "id": 1,
	  "name": "October Fest",
	  "customer": {
		"name": "John"
	  }
    },
	{
      "id": 3,
	  "name": "Christmas",
	  "customer": {
		"name": "Hakan"
	  }
    },
	{
      "id": 4,
	  "name": "Easter",
	  "customer": {
		"name": "Hakan"
	  }
    }
  ]
}

It returns an array with 3 items but @odata.count is 4. This is the my issue.

You know that, OData call 2 SQL Query for this url. First one to get data. Second one to get count. I checked SQL Queries in console.

First Query like that:

Select a.id, a.Name, c.Name
From Activity as a
	Inner Join Customer As c On (a.CustomerId = c.Id)
Where c.IsDeleted = false

Second Query like that:

Select Count(*) From Activity

Why do OData not join $expand to SQL query for getting count?

My example may be not valuable. But you can think this issue with authorization.

In addition, this issue break my pagination. Because I consider count of pages according to @odata.count

How can I solve this problem?
What can I do?
Do you think I did something wrong?

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 OData query at /odata/activity with $expand, $select, $top, and $count against the EF Core model using HasQueryFilter. Compare the generated data and count SQL, then trace the $count and $expand query-processing paths. Done means @odata.count reflects the filtered result set and pagination remains correct.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.