The LINQ expression 'OUTER APPLY Projection Mapping in EF .NET Core 5 Exception

拜拜、爱过 提交于 2021-02-11 17:35:42

问题


After migrating from .NET Core 2.x to .NET Core 5.0, we are facing this problem.

Error: (Added as a CODE for better readability)

 The LINQ expression 'OUTER APPLY Projection Mapping:
(
    SELECT e0.Id, e0.FirstName, e0.MiddleName, e0.LastName
    FROM Employees AS e0
    WHERE (((e0.Status != 4) && EXISTS (
        Projection Mapping:
        SELECT 1
        FROM FunctionRoles AS f0
        WHERE t.Id == f0.SchoolId)) && (e0.FunctionRoleId == (Projection Mapping:
            EmptyProjectionMember -> 0
        SELECT TOP(1) f1.Id
        FROM FunctionRoles AS f1
        WHERE (t.Id == f1.SchoolId) && (f1.Name == 'Manager')))) && (t.Id == e0.SchoolId)
) AS t0' could not be translated. Either rewrite the query in a form that can be translated, 
or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. 
See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

The code part:

using (var dbContext = _contextProvider.CreateContext())
        {
            var school = dbContext.Set<Domain.Model.School>()
                .Where(s => s.Id == schoolId)
                .Select(s => new SchoolSummaryDto
                {
                    

                    //... Some other properties

                    DocumentTemplates = s.DocumentTemplates != null ? s.DocumentTemplates.Select(a => new DocumentTemplateDto
                    { Id = a.Id, Description = a.Description, SchoolId = a.SchoolId, FileName = a.FileName, DocumentTemplateTypeId = a.DocumentTemplateTypeId }).ToList() : new List<DocumentTemplateDto>(),

                    // This below chunk is causing problem.
                    Signers = s.Employees != null ? s.Employees.AsEnumerable().Where(
                        e => e.Status != PersistentStatusEnum.Removed &&
                        e.FunctionRoleId == s.FunctionRoles.AsEnumerable().Single(
                        b => b.Name == FunctionRolesEnum.Manager.ToString()).Id).AsEnumerable().Select(
                        a => new NameValueType { Id = a.Id, Name = string.Format("{0} {1} {2}", a.FirstName, a.MiddleName, a.LastName) }).ToList() : new List<NameValueType>(),
                    // .. Error chunk ends here

                    ContactPerson = s.ContactPerson,
                    Email = s.Email,
                    PhoneNumber = s.PhoneNumber,
                    SchoolId = s.Id,
                    SchoolName = s.Name,
                    Website = s.Website,
                    IsEnabled = s.IsEnabled,
                    IsRegistered = s.IsRegistered
                }).FirstOrDefault();

        }

What I tried: As per these Microsoft links, Breaking Changes and Queryable projection not supported, I tried and applied changes AsEnumerable() accordingly as you can see above.

What changes are required now?

Libraries and Enviornment:

  1. Database => MySql
  2. Library => Pomelo.EntityFrameworkCore.MySql (5.0.0-alpha.2) Nuget Link

I sense either this MySql library is causing issue or EF Core 5 breaking changes.

Edit 1:

public class FunctionRole:AuditableEntity
{
    public string Name { get; set; }
    public string Description { get; set; }
    public Guid SchoolId { get; set; }
    public virtual School School { get; set; }
}

public class School:AuditableEntity
{
    public bool IsRegistered { get; set; }
    public bool IsEnabled { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Website { get; set; }
    public string PhoneNumber { get; set; }
    public string ContactPerson { get; set; }
    public string ActivationCode { get; set; }

    public virtual ICollection<FunctionRole> FunctionRoles { get; set; }

    public virtual ICollection<DocumentTemplate> DocumentTemplates { get; set; }
    

}

回答1:


I think it works with EF 2.x, because it silently evaluates this query on the client side.

Consider to rewrite query:

 var query = 
   from s in dbContext.Set<Domain.Model.School>()
   where s.Id == schoolId
   from r in s.FunctionRoles
      .Where(b => b.Name == FunctionRolesEnum.Manager.ToString())
      .Take(1).DefaultIfEmpty()
   select new SchoolSummaryDto
   {
                    
      //... Some other properties

      DocumentTemplates = s.DocumentTemplates
         .Select(a => new DocumentTemplateDto
         { 
            Id = a.Id, 
            Description = a.Description, 
            SchoolId = a.SchoolId, 
            FileName = a.FileName, 
            DocumentTemplateTypeId = a.DocumentTemplateTypeId 
         })
         .ToList(),

       Signers = s.Employees
          .Where(e => e.Status != PersistentStatusEnum.Removed 
                      && e.FunctionRoleId == r.Id)
          .Select(a => new NameValueType 
          { 
              Id = a.Id, 
              Name = a.FirstName + " " + a.MiddleName + " " + a.LastName 
          })
          .ToList(),

       ContactPerson = s.ContactPerson,
       Email = s.Email,
       PhoneNumber = s.PhoneNumber,
       SchoolId = s.Id,
       SchoolName = s.Name,
       Website = s.Website,
       IsEnabled = s.IsEnabled,
       IsRegistered = s.IsRegistered
    };

var school = query.FirstOrDefault();

You don't have to check for nulls, AsEnumerable is not needed, string.Format can be not translatable to the SQL.



来源:https://stackoverflow.com/questions/65645691/the-linq-expression-outer-apply-projection-mapping-in-ef-net-core-5-exception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!