Episode Details
Back to Episodes
LINQ to SQL: Magic or Mayhem?
Published 5 months, 2 weeks ago
Description
Have you ever written a LINQ query that worked perfectly in C#, but when you checked the SQL it generated, you wondered—how on earth did it get to *that*? In this session, you’ll learn three things in particular: how expression trees control translation, how caching shapes performance and memory use, and what to watch for when null logic doesn’t behave as expected. If you’ve suspected there’s black-box magic inside Entity Framework Core, the truth is closer to architecture than magic. EF Core uses a layered query pipeline that handles parsing, translation, caching, and materialization behind the scenes. First we’ll look at how your LINQ becomes an expression tree, then the provider’s role, caching, null semantics, and finally SQL and materialization. And it all starts right at the beginning: what actually happens the moment you run a LINQ query.From LINQ to Expression TreesWhen you write a LINQ query, the code isn’t automatically fluent in SQL. LINQ is just C#—it doesn’t know anything about databases or tables. So when you add something like a `Where` or a `Select`, you’re really calling methods in C#, not issuing commands to SQL. The job of Entity Framework Core is to capture those calls into a form it can analyze, before making any decisions about translation or execution. That capture happens through expression trees. Instead of immediately hitting the database, EF Core records your query as a tree of objects that describe each part. A `Where` clause doesn’t mean “filter rows” yet—it becomes a node in the tree that says “here’s a method call, here’s the property being compared, and here’s the constant value.” At this stage, nothing has executed. EF is simply documenting intent in a structured form it can later walk through. One way to think about it is structure before meaning. Just like breaking a sentence into subject and verb before attempting a translation, EF builds a tree where joins, filters, projections, and ordering are represented as nodes. Only once this structure exists can SQL translation even begin. EF Core depends on expression trees as its primary mechanism to inspect LINQ queries before deciding how to handle them. Each clause you write—whether a join or a filter—adds new nodes to that object model. For example, a condition like `c.City == "Paris"` becomes a branch with left and right parts: one pointing to the `City` property, and one pointing to the constant string `"Paris"`. By walking this structure, EF can figure out what parts of your query map to SQL and what parts don’t. Behind the scenes, these trees are not abstract concepts, but actual objects in memory. Each node represents a method call, a property, or a constant value—pieces EF can inspect and categorize. This design gives EF a reliable way to parse your query without executing it yet. Internally, EF treats the tree as a model, deciding which constructs it can send to SQL and which ones it must handle in memory. This difference explains why some queries behave one way in LINQ to Objects but fail in EF. Imagine you drop a custom helper function inside a lambda filter. In memory, LINQ just runs it. But with EF, the expression tree now contains a node referring to your custom method, and EF has no SQL equivalent for that method. At that point, you’ll often notice a runtime error, a warning, or SQL falling back to client-side evaluation. That’s usually the signal that something in your query isn’t translatable. The important thing to understand is that EF isn’t “running your code” when you write it. It’s diagramming it into this object tree. And if a part of that tree doesn’t correspond to a known SQL pattern, EF either stops or decides to push that part of the work into memory, which can be costly. Performance issues often show up here—queries that seem harmless in C# suddenly lead to thousands of rows being pulled client-side because EF couldn’t translate one small piece. That’s why expression trees matter to developers working with EF. They are