Course contentsShow
← C#
Lesson 1142 of 1,90810. Entity Framework Core ModelingFree lesson

Query Result Materialization

Understand the impact of materialization on object allocation and GC pressure.

Understanding Query Result Materialization

In this lesson, you will learn how Entity Framework Core transforms raw database data into C# objects and why this process directly impacts your application’s memory efficiency and Garbage Collector (GC) pressure.

What is Materialization?

"Materialization" is the process where EF Core takes the rows returned by your SQL query and converts them into instances of your entity classes. When you execute a query like context.Products.ToList(), EF Core doesn't just hold the raw data; it maps every column value into the corresponding property of a new Product object.

This process involves several behind-the-scenes operations:

  1. Instantiation: EF Core uses reflection (or compiled expressions) to create a new instance of your class.
  2. Population: It assigns values from the database reader to your object's properties.
  3. Change Tracking: The object is registered with the ChangeTracker, which creates additional overhead to monitor the entity's state.

The Hidden Cost: Object Allocation and GC Pressure

Every time you materialize a large result set, you are flooding the managed heap with new objects. If you query 10,000 records, you are creating 10,000 instances of your entity class, plus the associated tracking entries.

Consider this scenario:

// High GC Pressure: Materializes thousands of objects
var allOrders = context.Orders.ToList(); 

When these objects fall out of scope, the .NET Garbage Collector must work harder to clean them up. This leads to "GC Pressure," which can cause micro-stutters or increased CPU usage in high-traffic applications. If you don’t need to modify these records, materializing full entity objects is often wasteful.

Mitigation Strategies

To minimize this impact, use projection (.Select()) to fetch only the specific data you need into lightweight DTOs (Data Transfer Objects) or anonymous types. Because these projected objects aren't tracked by the ChangeTracker, they have a significantly smaller memory footprint.

// Lower GC Pressure: Projects only necessary data
var orderSummaries = context.Orders
    .Select(o => new { o.Id, o.Total }) 
    .ToList();

By projecting, you bypass the creation of heavy entity proxies and reduce the number of objects the Garbage Collector needs to manage.

Key Takeaway: Materializing full entities forces EF Core to allocate memory for every property and tracking entry, creating GC pressure that can be avoided by using projections for read-only operations.