1/13
Microsoft documentation for EFCore.
Name | Mastery | Learn | Test | Matching | Spaced |
---|
No study sessions yet.
EFCore will always try to evaluate query on server side, but when it can't and will evaluate it on client side? when we shouldn't make it evaluate in client side, as it will throw runtime exception?
Client evaluation in the top-level projection
In the following example, a helper method is used to standardize URLs for blogs, which are returned from a SQL Server database. Since the SQL Server provider has no insight into how this method is implemented, it isn't possible to translate it into SQL. All other aspects of the query are evaluated in the database, but passing the returned URL
through this method is done on the client.
var blogs = await context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(
blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog.Url) })
.ToListAsync();
Unsupported client evaluation
While client evaluation is useful, it can result in poor performance sometimes. Consider the following query, in which the helper method is now used in a where filter. Because the filter can't be applied in the database, all the data needs to be pulled into memory to apply the filter on the client. Based on the filter and the amount of data on the server, client evaluation could result in poor performance. So Entity Framework Core blocks such client evaluation and throws a runtime exception.
var blogs = await context.Blogs
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToListAsync();
what may cause Memory leak in EFCore Evaluation?
how to force EFCore to evaluate in client side? when we may need that?
Potential memory leak in client evaluation
Since query translation and compilation are expensive, EF Core caches the compiled query plan. The cached delegate may use client code while doing client evaluation of top-level projection. EF Core generates parameters for the client-evaluated parts of the tree and reuses the query plan by replacing the parameter values. But certain constants in the expression tree can't be converted into parameters. If the cached delegate contains such constants, then those objects can't be garbage collected since they're still being referenced. If such an object contains a DbContext or other services in it, then it could cause the memory usage of the app to grow over time. This behavior is generally a sign of a memory leak. EF Core throws an exception whenever it comes across constants of a type that can't be mapped using current database provider. Common causes and their solutions are as follows:
Using an instance method: When using instance methods in a client projection, the expression tree contains a constant of the instance. If your method doesn't use any data from the instance, consider making the method static. If you need instance data in the method body, then pass the specific data as an argument to the method.
Passing constant arguments to method: This case arises generally by using this
in an argument to client method. Consider splitting the argument in to multiple scalar arguments, which can be mapped by the database provider.
Other constants: If a constant is come across in any other case, then you can evaluate whether the constant is needed in processing. If it's necessary to have the constant, or if you can't use a solution from the above cases, then create a local variable to store the value and use local variable in the query. EF Core will convert the local variable into a parameter.
Explicit client evaluation
You may need to force into client evaluation explicitly in certain cases like following
The amount of data is small so that evaluating on the client doesn't incur a huge performance penalty.
The LINQ operator being used has no server-side translation.
In such cases, you can explicitly opt into client evaluation by calling methods like AsEnumerable
or ToList
(AsAsyncEnumerable
or ToListAsync
for async). By using AsEnumerable
you would be streaming the results, but using ToList
would cause buffering by creating a list, which also takes additional memory. Though if you're enumerating multiple times, then storing results in a list helps more since there's only one query to the database. Depending on the particular usage, you should evaluate which method is more useful for the case.
var blogs = context.Blogs
.AsAsyncEnumerable()
.Where(blog => StandardizeUrl(blog.Url).Contains("dotnet"))
.ToListAsync();
how to change default tracking behaviour?
When it’s better to use Tracking over No-Tracking? what’s better than both of them in that case?
The default tracking behavior can be changed at the context instance level:
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = await context.Blogs.ToListAsync();
Tracking vs. No-Tracking Queries
Tracking Queries (Default)
EF Core remembers loaded entities (like a notepad).
Performs identity resolution (returns the same instance if already loaded).
Example:
var customer1 = db.Customers.First(); // Tracked
var customer2 = db.Customers.First(); // Same instance as customer1
No-Tracking Queries (AsNoTracking
)
Faster (no change tracking overhead).
No identity resolution—each query returns a new object, even if it’s the same data.
Example:
var customer1 = db.Customers.AsNoTracking().First(); // New instance
var customer2 = db.Customers.AsNoTracking().First(); // Different instance
Hybrid: No-Tracking + Identity Resolution (AsNoTrackingWithIdentityResolution
)
Best of both: No long-term tracking, but avoids duplicates in a single query.
Uses a temporary tracker (discarded after query execution).
Example:
var customers = db.Customers.AsNoTrackingWithIdentityResolution().ToList();
// Same entity = same instance, but not tracked after the query.
In Projection, when does it track and when doesn’t it track entity?
Tracking and custom projections
Even if the result type of the query isn't an entity type, EF Core will still track entity types contained in the result by default. In the following query, which returns an anonymous type, the instances of Blog
in the result set will be tracked.
var blog = context.Blogs
.Select(
b =>
new { Blog = b, PostCount = b.Posts.Count() });
If the result set contains entity types coming out from LINQ composition, EF Core will track them.
C#Copy
var blog = context.Blogs
.Select(
b =>
new { Blog = b, Post = b.Posts.OrderBy(p => p.Rating).LastOrDefault() });
If the result set doesn't contain any entity types, then no tracking is done. In the following query, we return an anonymous type with some of the values from the entity (but no instances of the actual entity type). There are no tracked entities coming out of the query.
var blog = context.Blogs
.Select(
b =>
new { Id = b.BlogId, b.Url });
EF Core supports doing client evaluation in the top-level projection. If EF Core materializes an entity instance for client evaluation, it will be tracked. Here, since we're passing blog
entities to the client method StandardizeURL
, EF Core will track the blog instances too.
var blogs = await context.Blogs
.OrderByDescending(blog => blog.Rating)
.Select(
blog => new { Id = blog.BlogId, Url = StandardizeUrl(blog) })
.ToListAsync();
public static string StandardizeUrl(Blog blog)
{
var url = blog.Url.ToLower();
if (!url.StartsWith("http://"))
{
url = string.Concat("http://", url);
}
return url;
}
EF Core doesn't track the keyless entity instances contained in the result. But EF Core tracks all the other instances of entity types with a key according to rules above.