Using Anonymous Types with Entity Framework Queries

Shaping Data Without Extra Classes

Anonymous types in C# allow developers to create lightweight, on-the-fly data structures without defining separate model or DTO classes. When combined with Entity Framework (EF), they provide a powerful mechanism to project data into custom shapes – ideal for reports, dashboards, and lightweight data displays.

Instead of fetching full entities (which can be memory-heavy and slower), anonymous types let you select only the properties you need, keeping queries lean, efficient, and type-safe.


πŸ”Ή What Are Anonymous Types in EF?

Anonymous types are compiler-generated objects created with the new { } syntax. They are immutable and type-safe, but have no explicit class name. This makes them perfect for temporary data shaping inside LINQ to Entities queries.

Example:

var result = new { Id = 1, Name = "Alice", Score = 95 };
Console.WriteLine($"{result.Name} scored {result.Score}");

The compiler automatically infers the property names and types, creating a read-only class behind the scenes. In EF, this same principle applies β€” you can project data directly into anonymous types when querying entities.


πŸ”Ή Why Use Anonymous Types in EF Queries?

When working with EF, each entity typically maps to a database table. However, you rarely need every column from a table. Anonymous types let you:

  • Retrieve only the columns you need, improving performance.
  • Combine data from multiple entities into one compact result.
  • Create ad hoc projections for UI binding or JSON output.
  • Avoid defining temporary model classes for every custom shape.

This approach minimises memory footprint, reduces SQL payload, and speeds up query execution.


🧱 Example: Projecting Specific Columns

Instead of fetching the entire Student entity, you can select just the necessary data:

using (var context = new SchoolContext())
{
    var studentSummaries = context.Students
        .Where(s => s.Grade > 85)
        .Select(s => new
        {
            s.FirstName,
            s.LastName,
            s.Grade
        })
        .ToList();

    foreach (var s in studentSummaries)
        Console.WriteLine($"{s.FirstName} {s.LastName} - {s.Grade}");
}

βœ… Explanation:

  • .Select() shapes each entity into a new anonymous type.
  • EF translates the query into SQL that retrieves only FirstName, LastName, and Grade.
  • The anonymous object is materialised into memory without creating full entity objects.

This reduces database load and network transfer dramatically.


πŸ”Ή Combining Multiple Entities

Anonymous types shine when you need to combine related data without defining a custom class.

Example:

var orderSummaries = context.Orders
    .Where(o => o.Total > 100)
    .Select(o => new
    {
        o.OrderId,
        o.Customer.Name,
        o.OrderDate,
        TotalItems = o.OrderDetails.Count,
        o.Total
    })
    .ToList();

βœ… Explanation:

  • EF automatically performs the join between Orders and Customers.
  • The projection combines fields from both entities into a single anonymous type.
  • This avoids the need for a separate β€œOrderSummary” class.

πŸ”Ή Joining Tables with Anonymous Types

You can also create combined results using explicit joins:

var customerOrders = from c in context.Customers
                     join o in context.Orders on c.CustomerId equals o.CustomerId
                     select new
                     {
                         CustomerName = c.Name,
                         o.OrderId,
                         o.Total
                     };

βœ… Result:
EF translates the join into a single SQL statement returning customer names and their order totals, all projected into an anonymous structure.


πŸ”Ή Nested Anonymous Types

Anonymous types can contain other anonymous types β€” useful for hierarchical projections such as JSON-like structures:

var customerProfiles = context.Customers
    .Select(c => new
    {
        c.Name,
        Contact = new { c.Email, c.Phone },
        Orders = c.Orders.Select(o => new { o.OrderId, o.Total }).ToList()
    })
    .ToList();

βœ… Explanation:
This creates a nested structure like:

[
  {
    "Name": "Alice",
    "Contact": { "Email": "a@example.com", "Phone": "12345" },
    "Orders": [
      { "OrderId": 1, "Total": 200 },
      { "OrderId": 2, "Total": 350 }
    ]
  }
]

Perfect for generating structured output for APIs or front-end apps.


πŸ”Ή Anonymous Types vs DTOs

FeatureAnonymous TypesDTO (Data Transfer Object)
DefinitionInline, compiler-generatedExplicit class
ReusabilityLimited to local scopeReusable across layers
ImmutabilityRead-onlyCustomisable
Use CaseQuick projections, ad hoc queriesAPI models, external data exchange

βœ… Guideline:
Use anonymous types for internal, read-only projections within a single method or short pipeline.
Use DTOs when passing data across layers, returning from APIs, or storing long-term results.


πŸ”Ή Deferred Execution and Anonymous Types

Like all LINQ to Entities queries, projections into anonymous types use deferred execution β€” the SQL runs only when you enumerate the query.

Example:

var query = context.Products
    .Select(p => new { p.Name, p.Price }); // No SQL yet
var list = query.ToList(); // SQL executes here

βœ… Benefit:
You can compose and refine your query before it runs β€” improving performance and clarity.


πŸ” Performance and Best Practices

StrategyDescriptionExample
Project EarlySelect only required fields.Select(x => new { x.Name })
Avoid Client EvaluationEnsure EF translates logic to SQLAvoid methods unsupported by SQL
Reuse Query LogicStore reusable expressions in helper methodsExpression<Func<T,bool>>
Debug SQLUse EF logging or Profiler to inspect generated SQLcontext.Database.Log

Anonymous projections are fast because EF executes them as direct SQL SELECT statements, fetching only the needed columns.


πŸ“š Summary

ConceptDescriptionExample
Anonymous TypesTemporary, compiler-generated objectsnew { Name = "Alice" }
EF ProjectionsMap entity data to custom shapes.Select(x => new { x.Id, x.Name })
Nested TypesAnonymous types inside othersnew { Contact = new { Email } }
Deferred ExecutionQuery executes when enumerated.ToList()
EfficiencyRetrieve minimal, precise dataProject early and filter early

βœ… Best Practices

  • Use anonymous types for quick, focused data shaping.
  • Keep them local to a method or query pipeline.
  • Prefer explicit DTOs for reusable or API-facing data.
  • Profile SQL output to confirm projections are efficient.

πŸ’‘ Conclusion

Using anonymous types within Entity Framework queries allows developers to streamline data access, improve performance, and avoid unnecessary complexity.
They enable fine-grained control over what data is fetched, offering a clean, expressive syntax for shaping query results β€” all while maintaining the safety and efficiency of strongly-typed LINQ queries.

Mastering this technique is key to writing modern, optimised, and elegant EF queries that focus only on the data that truly matters.