Odata [EnableQuery] attribute makes EF Core crash on high requests amount
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 30/100
Research direction
Start with the OfficeDtoController.GetOfficeDto entry point and the GetOffices method shown in the issue. Reproduce the example request with $count under concurrent load, comparing it with the request without $count. Done means identifying and resolving the concurrent DbContext operation without regressing the OData query behavior.
Written by the indexing model from the issue text.
Description
I use ASP.NET Wen API on NET 5 and the following NuGets:
Microsoft.AspNetCore.OData => 7.5.4
Microsoft.Data.OData => 5.8.4
Microsoft.OData.Core => 7.8.1
Microsoft.EntityFrameworkCore => 5.0.2
(I have tried with Microsoft.AspNetCore.OData 8.0.0-preview3 and the problem is the same)
#23891 - How the problem started. But this is a different problem so I decided to post a new issue.
In my Odata controller I Use [EnableQuery(EnsureStableOrdering = false)]. Stable ordering is because of some custom Order by which I need in my code. Example in the mentioned Issue above
The problem however is with the [EnableQuery] attribute in general. When I have this attribute in the controller on high load, which means more than 150 request in a minute at the same endpoint I get a lot of the following exception:
"System.InvalidOperationException","Message":"A second operation was started on this context before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext."
"StackTraceString":" at Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()\r\n at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable
1.Enumerator.MoveNext()\r\n at System.Linq.Enumerable.Single[TSource](IEnumerable1 source)","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":null,"HResult":-2146233079,"Source":"Microsoft.EntityFrameworkCore"
I have used testing tool which send that kind of request to my endpoind (Result is around 240 requests in a minute with 1s delay between each) and most of the requests succeed, like maybe around 85% - 90% of them, however the failed requests get the exception above.
I needed some time to figure out what is happening, but when I remove the [EnableQuery] attribute everything was fine. No exception on any level of requests amount.
Here some code:
public class OfficeDtoController : ODataController
{
private readonly IOfficesService _officesService;
public OfficeDtoController(IOfficesService officesService)
{
_officesService = officesService;
}
[HttpGet]
[EnableQuery(EnsureStableOrdering = false)]
public IActionResult GetOfficeDto(ODataQueryOptions<OfficeDto> queryOptions, Guid? id = null, string sortColumn = "", string sortOrder = "", int? top = null, int? skip = null)
{
IQueryable<OfficeDto> officeDto = _officesService.GetOffices(id, sortColumn, sortOrder, top, skip);
return Ok(officeDto);
}
And the GetOffices method:
public IQueryable<OfficeDto> GetOffices(Guid? id, string sortColumn, string sortOrder, int? top, int? skip)
{
IQueryable<Office> query = dbSet;
query = query
.Where(z => !z.Deleted);
var list = query.Select(x =>
new OfficeDto()
{
Id = x.Id,
ZipCode = x.ZipCode,
Active = x..Active,
Employees = x.XrefOfficesEmployees
.OrderBy(y => y.Order)
.Select(y => new IdAndName()
{
Value = y.EmployeeId,
Text = y.Employee.FirstName + " " + y.Employee.LastName,
Order = y.Order
})
});
switch (sortColumn)
{
case "employees":
if (sortOrder == "desc")
{
officeDto = officeDto.OrderByDescending(b => b.Employees.Select(a => a.Text).FirstOrDefault( ));
}
else
{
officeDto = officeDto.OrderBy(b => b.Employees.Select(a => a.Text).FirstOrDefault( ));
}
}
return list;
}
Here is the example URL:
api/OfficeDto?$count=true&$top=20&$skip=0&$select=id,zipcode,employees&$filter=(active eq true)
The exception I get assumes there is some wrong async/await usage, but as it can be seen this is Odata GET request and I do not use async/await anywhere. Maybe there is problem in the communication between EF Core and Odata.
EDIT:
I have found out that without $count it works fine. $Count makes second query to the DB apart from the $Select so I guess this is the problem. Any toughts?
- Dominant language
- C#
- Stars
- 14.8k
- Forks
- 3.4k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 134
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from dotnet/efcore
-
Difficulty 4/5 3-5 days Newbie friendliness 55/100
-
customer-reported
Difficulty 5/5 Over a week Newbie friendliness 38/100
-
area-cosmos area-vector-search
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
area-cosmos
Difficulty 5/5 Over a week Newbie friendliness 25/100
-
area-tools needs-design
Difficulty 4/5 3-5 days Newbie friendliness 25/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
:watch: Not Triaged 11.0 fundamentals/subsvc
Difficulty 2/5 1-3 hours Newbie friendliness 92/100
dotnet/AspNetCore.Docs#37699 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SubtitleEdit/subtitleedit#15108 · 1 comment ·
-
area/docs-content Bug pulumi/docs
Difficulty 1/5 1-3 hours Newbie friendliness 94/100
-
agentic-workflows untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 76/100