Search code examples
c#asynchronousblazorblazor-server-side

InvalidOperationException when fetching joined data with Entity Framework in Blazor Server


I'm working on a Blazor server-side project where I need to fetch and join data from multiple tables using Entity Framework Core in the OnInitializedAsync method. However, I'm encountering the following error:

InvalidOperationException: A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext.

Here is my code below:

protected override async Task OnInitializedAsync()
{

    PeopleTypes = await DbContext.PeopleTypes.Select(pts => new PeopleType
        {
            Id = pts.Id,
            TypeName = pts.TypeName
        }).ToListAsync() ?? new List<PeopleType>();

    Peoples = await DbContext.People.Select(pl => new People
        {
            Id = pl.Id,
            Name = pl.Name,
            CompanyId = pl.CompanyId,
            TypeId = pl.TypeId
        }).ToListAsync() ?? new List<People>();

    CompanyLists = await DbContext.CompanyList.Select(cl => new CompanyList
        {
            Id = cl.Id,
            CompanyName = cl.CompanyName
        }).ToListAsync() ?? new List<CompanyList>();

    ClassDetails = await DbContext.ClassSessionsDetails
    .Where(csd => csd.CsID == CSId)
    .Where(csd => csd.CompanyId == selectedCompany)
    .Select(csd => new ClassSessionDetails
        {
            Id = csd.Id,
            CsID = csd.CsID
        }).ToListAsync();

    classMembersData = await DbContext.ClassSessionsDetails
        .Join(DbContext.ClassSessionsMembers,
            csd => csd.Id,
            csm => csm.CSD_Id,
            (csd, csm) => new { csd, csm })
        .Join(DbContext.People,
            combined => combined.csm.PeopleId,
            people => people.Id,
            (combined, people) => new { combined.csd, combined.csm, people })
        .GroupJoin(DbContext.CompanyList,
            combined => combined.people.CompanyId,
            company => company.Id,
            (combined, companies) => new { combined.csd, combined.csm, combined.people, company = companies.FirstOrDefault() })
        .GroupJoin(DbContext.PeopleTypes,
            combined => combined.people.TypeId,
            peopleType => peopleType.Id,
            (combined, peopleTypes) => new { combined.csd, combined.csm, combined.people, combined.company, peopleType = peopleTypes.FirstOrDefault() })
        .Select(result => new ClassMembers
            {
                PeopleId = result.people.Id,
                Name = result.people.Name,
                CompanyId = result.company.Id,
                CompanyName = result.company.CompanyName,
                PeopleTypeId = result.peopleType.Id,
                PeopleTypeName = result.peopleType.TypeName
            }).ToListAsync();

    await base.OnInitializedAsync();
}

Does anyone have suggestions on how to resolve this issue, or how I can improve my query to avoid concurrent operation conflicts? Thank you.


Solution

  • Merge multiple queries into one query to avoid multiple asynchronous calls to DbContext. This can avoid concurrent operations and improve performance.

    Here is the sample

    protected override async Task OnInitializedAsync()
    {
        var result = await (
            from csd in DbContext.ClassSessionsDetails
            join csm in DbContext.ClassSessionsMembers on csd.Id equals csm.CSD_Id
            join p in DbContext.People on csm.PeopleId equals p.Id
            join cl in DbContext.CompanyList on p.CompanyId equals cl.Id into companyGroup
            from company in companyGroup.DefaultIfEmpty()
            join pt in DbContext.PeopleTypes on p.TypeId equals pt.Id into peopleTypeGroup
            from peopleType in peopleTypeGroup.DefaultIfEmpty()
            where csd.CsID == CSId && csd.CompanyId == selectedCompany
            select new ClassMembers
            {
                PeopleId = p.Id,
                Name = p.Name,
                CompanyId = company != null ? company.Id : (int?)null,
                CompanyName = company != null ? company.CompanyName : null,
                PeopleTypeId = peopleType != null ? peopleType.Id : (int?)null,
                PeopleTypeName = peopleType != null ? peopleType.TypeName : null
            }
        ).ToListAsync();
    
        classMembersData = result;
    
        await base.OnInitializedAsync();
    }