TagWith adds a comment to the SQL generated for an EF Core query, making it easier to correlate a LINQ query in your code with the SQL captured in logs.
Using TagWith
Use TagWith when you want to add your own descriptive text to a query:
var query = context.Products
.TagWith("Get active products")
.Where(product => product.IsActive)
.OrderBy(product => product.ProductId);
var products = await query.ToListAsync();
TagWith composes the query; it does not execute it. It returns an IQueryable<Product>, and ToListAsync() executes that query and materializes the results. See LINQ Queries for more about query composition and execution.
For this example, EF Core generates SQL similar to the following with SQLite:
-- Get active products
SELECT "p"."ProductId", "p"."IsActive", "p"."Name"
FROM "Products" AS "p"
WHERE "p"."IsActive"
ORDER BY "p"."ProductId"
The text passed to TagWith appears as a SQL comment before the query. The exact SQL syntax can vary by database provider, but the tag remains associated with the generated query.
TagWith does not change the filtering, ordering, projection, or result shape of the LINQ query. In this example, ToListAsync() returns a List<Product> containing the active products.
Using TagWithCallSite
Use TagWithCallSite when you want EF Core to tag the generated SQL automatically with the source file and line number where the method is called.
var query = context.Products
.TagWithCallSite()
.OrderBy(product => product.ProductId);
var products = await query.ToListAsync();
Like TagWith, TagWithCallSite composes the query; it does not execute it. ToListAsync() executes the query and materializes the results.
For this example, EF Core generates SQL similar to the following with SQLite:
-- File: C:\Project\ProductQueries.cs:48
SELECT "p"."ProductId", "p"."IsActive", "p"."Name"
FROM "Products" AS "p"
ORDER BY "p"."ProductId"
TagWithCallSite adds the file path and line number automatically, so you do not need to provide a custom tag string.
The exact file path and line number depend on where the method is called in your source code. The generated SQL syntax can also vary by database provider.
TagWithCallSite does not change the filtering, ordering, projection, or result shape of the query. In this example, ToListAsync() returns a List<Product> ordered by ProductId.
TagWith vs. TagWithCallSite
Both methods add identifying information to the SQL generated by EF Core, but they differ in where that information comes from.
| Method | What it adds | Use it when |
|---|---|---|
TagWith("text") |
A custom comment that you provide | You want a descriptive label that explains the purpose of the query |
TagWithCallSite() |
The source file and line number automatically | You want to locate the query in your source code |
Neither method changes the filtering, ordering, projection, or result shape of the query.
Additional TagWith Options
Multiple Tags
You can call TagWith more than once while composing the same query. The tags are cumulative and appear as separate comments in the generated SQL.
var products = await context.Products
.TagWith("Products query")
.TagWith("Active products only")
.Where(product => product.IsActive)
.OrderBy(product => product.ProductId)
.ToListAsync();
The generated SQL includes both tags:
-- Products query
-- Active products only
This can be useful when different parts of an application compose the same query and each part adds context about its purpose.
Multi-line Tags
TagWith also accepts multi-line strings. EF Core writes each line as part of the SQL comment block.
var products = await context.Products
.TagWith(
"""
Products query
Active products only
""")
.Where(product => product.IsActive)
.OrderBy(product => product.ProductId)
.ToListAsync();
The generated SQL includes each line of the tag as a separate SQL comment:
-- Products query
-- Active products only
Multi-line tags can be useful when a single short label is not enough to describe the purpose of a query.
Query Tags Are Not Parameterizable
EF Core treats query tags as string literals that are included directly in the generated SQL.
Because of this, query tags are not parameterizable. A compiled query cannot accept the query tag as a parameter.
This limitation applies to the query tag itself and does not change how normal query values are parameterized by EF Core.
External Resources - TagWith
The following videos provide practical demonstrations of how query tags help identify EF Core queries in SQL logs and profiling tools. They complement the article by showing how tags appear and are used in real query-inspection scenarios.
Video 1 - EF Core Query Tags and logging - Jernej Kavka (JK)
Jernej Kavka explains the lack of context developers can face when inspecting generated SQL and demonstrates how query tags can make a query easier to identify. The presentation also shows the tag in captured SQL and compares SQL-level query tags with additional logging context.
The video was recorded in 2020, so some version-specific discussion is historical and it does not cover TagWithCallSite. Its main value for this article is the practical logging demonstration rather than current EF Core version guidance.
Key timestamps:
- 2:58 — Introduces query tags as a way to add identifying text to generated SQL and connect a query back to its source code.
- 8:01 — Demonstrates
TagWith("GetTweets")in code and verifies the resulting-- GetTweetscomment in the captured SQL log. - 9:22 — Shows
TagWithused together with logging scope to add SQL-level and logging-level context for the same query.
Video 2 - Entity Framework TagWith - Milton Sampaio
Milton Sampaio demonstrates TagWith and TagWithCallSite with SQL Server Profiler, showing how each one adds identifying comments to the SQL captured during query execution.
The TagWithCallSite section is particularly useful because it shows the generated source file path and line number directly in the profiler. The presenter also discusses a practical limitation: line numbers can change as the code evolves, so they should not be treated as stable identifiers over time.
Later in the video, the presenter introduces a custom TagComContexto extension. This is an additional custom implementation, not a built-in EF Core API.
Key timestamps:
- 5:52 — Introduces
TagWith("testeDaTag")and shows the resulting-- testeDaTagcomment in SQL Server Profiler. - 7:53 — Introduces
TagWithCallSite()and shows the generated source file path and line number (HomeController.cs:23) in SQL Server Profiler. - 8:41 — Explains the practical limitation of relying on the generated line number because later code changes can move the original call to a different line.
Summary
EF Core query tags add identifying comments to generated SQL without changing the filtering, ordering, projection, or result shape of the query.
- Use
TagWith("text")when you want to add your own descriptive label. - Use
TagWithCallSite()when you want EF Core to include the source file and line number automatically. - Multiple
TagWithcalls are cumulative. TagWithcan also use multi-line strings.- Query tags are not parameterizable and cannot be passed as parameters to compiled queries.
Query tags are part of query composition and do not execute the query. A terminal operation such as ToListAsync() executes and materializes the results.
Related Articles
- LINQ Queries — Learn how to build, compose, and execute EF Core queries.
- LINQ Methods — Learn how to use LINQ operators when composing EF Core queries.
FAQ
Does TagWith() execute the query?
No. TagWith() composes the IQueryable and adds identifying information that EF Core includes in the generated SQL. The query is executed by a terminal operation such as ToListAsync().
Does TagWith() change the results returned by the query?
No. A query tag does not change the filtering, ordering, projection, or result shape of the query. It adds identifying information as a comment in the generated SQL.
What is the difference between TagWith() and TagWithCallSite()?
TagWith() adds custom text that you provide.
TagWithCallSite() automatically adds the source file and line number where the method is called.
Can I add more than one tag to the same query?
Yes. Query tags are cumulative. If you call TagWith() multiple times while composing a query, EF Core includes each tag in the generated SQL.
Can query tags be parameterized?
No. EF Core treats query tags as string literals included in the generated SQL. A compiled query cannot accept a query tag as a parameter.