0

Error generated for warning

'Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning: The LINQ expression 'where Convert([p].Status, Enum).GetDisplayName().Contains(__searchBy_8)' could not be translated and will be evaluated locally.'. This exception can be suppressed or logged by passing event ID 'RelationalEventId.QueryClientEvaluationWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.

I am saving the value of status enum to the database table Complaints

public enum Status
{
    Pending = 0,        
    Error = 1,
    Cancelled = 2,
    Delayed = 3,        
    Resolved = 4
}

I have to apply filtering on a query against the search string along with some other filtering and I am trying to do this in following way

// Apply Relevant SearchModel filters first
var query = context.Complaints
                   .Include(s => s.Messages)
                   .ThenInclude(p => p.User).AsQueryable();
        
if (dtParams.StartDate != null && dtParams.EndDate != null)
{
    query = query.Where(s => s.CreatedAt >= dtParams.StartDate.Value.Date && 
                             s.CreatedAt <= dtParams.EndDate.Value.Date);
}

string searchBy = dtParams.Search?.Value;

if (!string.IsNullOrEmpty(searchBy))
{
    query = query.Where(r => r.ComplaintNo.Contains(searchBy) ||                                                                                      
                             r.CreatorUsername.Contains(searchBy) ||                                                                                      
                             (r.CreatedAt != null &&  r.CreatedAt.ToString().Contains(searchBy)) ||                                                                                                                                    
                             (r.Status.GetDisplayName().Contains(searchBy)) ||
                             r.Messages.Any(p => p.StatusDescription.Contains(searchBy))
                        );
}

// Convert the Db context to Custom ViewModel which will then be rendered on to a DataTable
var dtQuery = query.SelectMany(x => x.Messages, (complaint, message) => new { complaint, message })
                       .Select(p => new ListTableViewModel
                       {
                           ComplaintNo = $"<a href=\"{Url.Action("GetLabels", new { orderNo = p.complaint.ComplaintNo })}\" target=\"_blank\"> {p.complaint.ComplaintNo}</a>",                               
                            
                           Tracking = GenerateTrackingUrl(p.complaint),                               
                           Creator = p.complaint.CreatorUsername,
                           CreatedAt = p.complaint.CreatedAt.ToString("dd/MM/yy"),                               
                           Status = $"<span class=\"badge label-{p.complaint.Status}\">{p.complaint.Status.GetDisplayName()}</span>",
                           Info = p.message.StatusDescription
                       }).ToList(); 
                       

I was getting an exception like below

Error generated for warning 'Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning:
The LINQ expression 'where Convert([p].Status, Enum).GetDisplayName().Contains(__searchBy_8)' could not be translated and will be evaluated locally.'. This exception can be suppressed or logged by passing event ID 'RelationalEventId.QueryClientEvaluationWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.

The line causing this exception is where I am comparing the search text with value of enum

 (r.Status.GetDisplayName().Contains(searchBy))
 
 

How can i compare display name of enum to the Search string IF someone is searching for text Resolved , i have to fetch all records of Status Resolved from db

1 Answer 1

1

This warning occurs because GetDisplayName() is a custom method implemented in your code and cannot be accessed by the database or translated to any sort of sql statement. Therefore EF needs to load all entities from the database and performs filtering in memory (which you should avoid because filtering on the database is much faster).

What you need to to is "Reverse engineer" the term the user searched for to the actual enum value e.g. like so

var filteredStatus = Enum.GetValues<Status>()
                         .Where(value => value.GetDisplayName().Contains(searchBy))
                         .ToList();

and then in your query instead of using r.Status.GetDisplayName().Contains(searchBy) use filteredStatus.Contains(r.Status)

Sign up to request clarification or add additional context in comments.

4 Comments

Here Enum.GetValues is an array and not sure how can we apply Where to an Array. I am getting a compile exception at Where So i added like below and trying this solution now Enum.GetValues(typeof(Status)).Cast<Status>().Where(v
@Mat I'm sorry I used the wrong overload of GetValues() - I've updated my answer to the correct one
Can we apply this reverse engineering to Child class enums as well ? r.Messages.Any(p => p.Status.GetDisplayName().Contains(searchBy) )
@Mat I do not see the code you are mentioning in your comment in your original question and therefore I have no context - but in general yes this solution will work for other enums of child classes too

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.