Client vs. Server evaluation is a feature that makes it easier to write queries to the database because Entity Framework Core supports parts of the query being evaluated on the client and parts of it being pushed to the database.
In the following example, a helper method is used to combine the first name and last name from a SQL Server database.
private static string CombineNames(string firstName, string lastName)
{
return firstName + " " + lastName;
}
The SQL Server provider has no idea how this method is implemented, so it is not possible to translate it into SQL. All other aspects of the query are evaluated in the database, but combining the first name and last name through this method is performed on the client.
var author = context.Authors
.Where(a => a.AuthorId == 1)
.Select(au => new
{
FullName = CombineNames(au.FirstName, au.LastName)
}).FirstOrDefault();
Client/Server evaluation has some useful features, but in some cases, it can result in poor performance. In the following query, the helper method is now used in a filter, because this can't be performed in the database.
var authors = context.Authors
.Where(a => CombineNames(a.FirstName, a.LastName)
.Contains("John"))
.ToList();
All the data is pulled into memory, and then the filter is applied to the client. Depending on the amount of data, and how much of that data is filtered out, this could result in poor performance.
DbContext.OnConfiguring
when client evaluation occurs to either throw an exception or ignore it.protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Data Source=(localdb)\ProjectsV13;Initial Catalog=AuthorDB;")
.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
}
Now the configuration is added in the DbContext.OnConfiguring
to throw an exception. If a poorly performing query is found, it will throw the following exception with a warning.
You may need to force into client evaluation explicitly in certain cases like following
AsEnumerable
or ToList
(AsAsyncEnumerable
or ToListAsync
for async).AsEnumerable
you would be streaming the results, but using ToList
would cause buffering by creating a list, which also takes additional memory.var authors = context.Authors
.AsEnumerable()
.Where(a => CombineNames(a.FirstName, a.LastName)
.Contains("John"))
.ToList();