WEBVTT

1
00:00:00.080 --> 00:00:02.040
<v Speaker 1>Have you ever written the link U query that worked

2
00:00:02.040 --> 00:00:05.040
<v Speaker 1>perfectly in CRS, but when you checked the sequel it generated,

3
00:00:05.080 --> 00:00:07.000
<v Speaker 1>you wondered, how on earth did it get to that.

4
00:00:07.240 --> 00:00:09.919
<v Speaker 1>In this session you learn three things, in particular, how

5
00:00:09.960 --> 00:00:14.240
<v Speaker 1>expression trees control translation, how caching shapes performance and memory use,

6
00:00:14.519 --> 00:00:16.920
<v Speaker 1>and what to watch for when null logic doesn't behave

7
00:00:16.960 --> 00:00:20.320
<v Speaker 1>as expected. If you've suspected there's black box magic inside

8
00:00:20.399 --> 00:00:23.280
<v Speaker 1>Entity Framework COLL, the truth is closer to architecture than magic.

9
00:00:23.559 --> 00:00:27.920
<v Speaker 1>Ef core uses a layered query pipeline that handles passing, translation, catching,

10
00:00:27.960 --> 00:00:30.760
<v Speaker 1>and materialization behind the scenes. First, we'll look at how

11
00:00:30.800 --> 00:00:33.479
<v Speaker 1>your link you becomes an expression tree, than the provider's

12
00:00:33.560 --> 00:00:37.759
<v Speaker 1>role caching, null semantics, and finally sequel and materialization. And

13
00:00:37.799 --> 00:00:40.560
<v Speaker 1>it all starts right at the beginning. What actually happens

14
00:00:40.560 --> 00:00:44.200
<v Speaker 1>the moment you run a link query from link to

15
00:00:44.240 --> 00:00:47.399
<v Speaker 1>expression trees. When you write a link query, the code

16
00:00:47.439 --> 00:00:50.640
<v Speaker 1>isn't automatically fluent in SQL. Link is just cpar. It

17
00:00:50.679 --> 00:00:53.560
<v Speaker 1>doesn't know anything about databases or tables. So when you

18
00:00:53.600 --> 00:00:55.960
<v Speaker 1>add something like a weare or a select, you're really

19
00:00:55.960 --> 00:00:59.200
<v Speaker 1>calling methods in SHI, not issuing commands to SEQL. The

20
00:00:59.280 --> 00:01:01.799
<v Speaker 1>job of Entity framework core is to capture those calls

21
00:01:01.799 --> 00:01:05.079
<v Speaker 1>into a form it can analyze before making any decisions

22
00:01:05.079 --> 00:01:08.799
<v Speaker 1>about translation or execution. That capture happens through expression trees

23
00:01:08.879 --> 00:01:12.519
<v Speaker 1>instead of immediately hitting the database. Efcre records your query

24
00:01:12.560 --> 00:01:14.879
<v Speaker 1>as a tree of objects that describe each part. A

25
00:01:14.920 --> 00:01:17.920
<v Speaker 1>were clause doesn't mean filter rose yet it becomes a

26
00:01:18.000 --> 00:01:20.599
<v Speaker 1>node in the tree that says, here's a method call,

27
00:01:20.680 --> 00:01:23.640
<v Speaker 1>here's the property being compared, and here's the constant value.

28
00:01:23.959 --> 00:01:27.280
<v Speaker 1>At this stage, nothing has executed. EF is simply documenting

29
00:01:27.319 --> 00:01:29.640
<v Speaker 1>intent in a structured form it can later walk through.

30
00:01:29.959 --> 00:01:32.760
<v Speaker 1>One way to think about it is structure before meaning,

31
00:01:33.120 --> 00:01:35.439
<v Speaker 1>just like breaking a sentence into subject and verb before

32
00:01:35.439 --> 00:01:39.799
<v Speaker 1>attempting a translation. EF builds a tree where joints, filters, projections,

33
00:01:39.799 --> 00:01:43.159
<v Speaker 1>and ordering are represented as notes. Only once the structure

34
00:01:43.159 --> 00:01:46.439
<v Speaker 1>exists can sequel translation even begin. Ef core depends on

35
00:01:46.480 --> 00:01:49.879
<v Speaker 1>expression trees as its primary mechanism to inspect link equeries

36
00:01:49.879 --> 00:01:52.560
<v Speaker 1>before deciding how to handle them. Each clause, you write

37
00:01:52.640 --> 00:01:55.040
<v Speaker 1>whether a joint or a filter adds new nodes to

38
00:01:55.079 --> 00:01:58.920
<v Speaker 1>that object model. For example, a condition like c city elcutsaurser,

39
00:01:59.000 --> 00:02:01.519
<v Speaker 1>paris arzyl become a branch with left and right parts,

40
00:02:01.840 --> 00:02:04.239
<v Speaker 1>one pointing to the city property and one pointing to

41
00:02:04.280 --> 00:02:07.799
<v Speaker 1>the constant string paris. By walking this structure, EF can

42
00:02:07.840 --> 00:02:10.120
<v Speaker 1>figure out what parts of your query map to SQL

43
00:02:10.240 --> 00:02:12.960
<v Speaker 1>and what parts don't. Behind the scenes, these trees are

44
00:02:12.960 --> 00:02:16.639
<v Speaker 1>not abstract concepts, but actual objects in memory. Each node

45
00:02:16.919 --> 00:02:20.560
<v Speaker 1>represents a method, call, a property, or a constant value

46
00:02:20.879 --> 00:02:24.400
<v Speaker 1>pieces EF can inspect and categorize. This design gives EF

47
00:02:24.439 --> 00:02:27.240
<v Speaker 1>a reliable way to pass your query without executing it.

48
00:02:27.360 --> 00:02:30.919
<v Speaker 1>Yet internally, EF treats the tree as a model, deciding

49
00:02:30.960 --> 00:02:33.080
<v Speaker 1>which constructs it can send to SQL and which ones

50
00:02:33.120 --> 00:02:36.039
<v Speaker 1>it must handle in memory. This difference explains why some

51
00:02:36.120 --> 00:02:38.479
<v Speaker 1>queries behave one way in link to objects but fail

52
00:02:38.560 --> 00:02:41.639
<v Speaker 1>in EF. Imagine you drop a custom helper function inside

53
00:02:41.639 --> 00:02:44.039
<v Speaker 1>a lambda filter in memory link you just runs it,

54
00:02:44.240 --> 00:02:47.479
<v Speaker 1>but with EF, the expression tree now contains a node

55
00:02:47.520 --> 00:02:50.240
<v Speaker 1>referring to your custom method, and EF has no circle

56
00:02:50.280 --> 00:02:52.719
<v Speaker 1>equivalent for that method. At that point, you'll often notice

57
00:02:52.719 --> 00:02:55.360
<v Speaker 1>a runtime error, a warning or sequel falling back to

58
00:02:55.439 --> 00:02:58.400
<v Speaker 1>client side evaluation. That's usually the signal that something in

59
00:02:58.400 --> 00:03:01.719
<v Speaker 1>your query isn't translatable. The important thing to understand is

60
00:03:01.759 --> 00:03:04.159
<v Speaker 1>that EF isn't running your code when you write it,

61
00:03:04.159 --> 00:03:06.280
<v Speaker 1>it's diagramming it into this object tree, and if a

62
00:03:06.319 --> 00:03:09.000
<v Speaker 1>part of that tree doesn't correspond to a known SEQL pattern,

63
00:03:09.240 --> 00:03:12.039
<v Speaker 1>EF either stops or decides to push that part of

64
00:03:12.120 --> 00:03:15.319
<v Speaker 1>the work into memory, which can be costly. Performance issues

65
00:03:15.360 --> 00:03:17.919
<v Speaker 1>often show up here. Queries that seem harmless in C

66
00:03:18.120 --> 00:03:21.159
<v Speaker 1>sides suddenly to thousands of rows being pulled client side

67
00:03:21.240 --> 00:03:23.960
<v Speaker 1>because EF couldn't translate one small piece. And that's why

68
00:03:24.000 --> 00:03:27.439
<v Speaker 1>expression trees matter to developers working with EF. They aren't

69
00:03:27.439 --> 00:03:30.199
<v Speaker 1>just an internal detail, they are the roadmap EF uses

70
00:03:30.479 --> 00:03:33.639
<v Speaker 1>before SQL even enters the picture. Every link query is

71
00:03:33.680 --> 00:03:36.800
<v Speaker 1>first turned into this structural plan that EF studies carefully.

72
00:03:37.199 --> 00:03:40.080
<v Speaker 1>Whether a query succeeds, fails, or slows down often depends

73
00:03:40.120 --> 00:03:42.520
<v Speaker 1>on what that plan looks like. But there's still one

74
00:03:42.560 --> 00:03:45.439
<v Speaker 1>more step in the process. Once EF has that expression tree,

75
00:03:45.479 --> 00:03:47.280
<v Speaker 1>it can't just ship it off to the database. It

76
00:03:47.319 --> 00:03:50.080
<v Speaker 1>needs a gatekeeper. Something has to decide whether each part

77
00:03:50.120 --> 00:03:52.759
<v Speaker 1>of the tree is SQL legal or something that should

78
00:03:52.759 --> 00:03:55.000
<v Speaker 1>never leave C culls. And that's where the next stage

79
00:03:55.039 --> 00:03:58.680
<v Speaker 1>come in. The gatekeeper. EF cores query provider. Not every

80
00:03:58.759 --> 00:04:01.199
<v Speaker 1>query you write in CS is destined to become SQL.

81
00:04:01.240 --> 00:04:03.639
<v Speaker 1>There's a checkpoint in the middle of the pipeline, and

82
00:04:03.759 --> 00:04:06.240
<v Speaker 1>its role is to decide what moves forward and what

83
00:04:06.319 --> 00:04:09.919
<v Speaker 1>gets blocked. This checkpoint is implemented by ef core's query

84
00:04:09.960 --> 00:04:13.639
<v Speaker 1>provider component, which evaluates whether the expression tree's nodes can

85
00:04:13.680 --> 00:04:16.240
<v Speaker 1>be mapped to SQL or need to be handled in memory.

86
00:04:16.519 --> 00:04:18.720
<v Speaker 1>You can picture the provider like a bouncer at a club.

87
00:04:19.000 --> 00:04:21.399
<v Speaker 1>Everyone can show up in line, but only the queries

88
00:04:21.439 --> 00:04:24.240
<v Speaker 1>dressed in SQL compatible patterns actually get inside. The rest

89
00:04:24.279 --> 00:04:27.079
<v Speaker 1>either get turned away or get redirected for client side handling.

90
00:04:27.199 --> 00:04:30.000
<v Speaker 1>It's not about being picky or arbitrary. The provider is

91
00:04:30.079 --> 00:04:33.160
<v Speaker 1>enforcing the limits of translation link Q can represent far

92
00:04:33.199 --> 00:04:36.399
<v Speaker 1>more than relational databases will ever understand. Ef core has

93
00:04:36.399 --> 00:04:38.959
<v Speaker 1>to walk the expression tree and ask of each node,

94
00:04:39.319 --> 00:04:41.399
<v Speaker 1>is this something SQL can handle or is it something

95
00:04:41.800 --> 00:04:44.800
<v Speaker 1>net alone can execute. That call gets made early before

96
00:04:44.800 --> 00:04:47.639
<v Speaker 1>CECL generation starts, which is why you sometimes see runtime

97
00:04:47.759 --> 00:04:51.240
<v Speaker 1>errors upfront instead of confusing results later. For the developer,

98
00:04:51.279 --> 00:04:54.759
<v Speaker 1>the surprise often comes from uneven support. Many constructs map cleanly,

99
00:04:55.000 --> 00:04:59.120
<v Speaker 1>where select, order buy usually translate with no issue. Others

100
00:04:59.120 --> 00:05:01.839
<v Speaker 1>are more complicated. For example, group by can be more

101
00:05:01.839 --> 00:05:05.319
<v Speaker 1>difficult to translate, and depending on the provider and the scenario,

102
00:05:05.439 --> 00:05:08.240
<v Speaker 1>it may either fail outright or produce sequel that isn't

103
00:05:08.279 --> 00:05:11.199
<v Speaker 1>very efficient. Developers see this often enough that it's a

104
00:05:11.240 --> 00:05:14.199
<v Speaker 1>known caution point, though the exact behavior depends on the

105
00:05:14.199 --> 00:05:17.160
<v Speaker 1>provider's translation rules. The key thing the provider is doing

106
00:05:17.160 --> 00:05:19.399
<v Speaker 1>here is pattern matching. It isn't inventing school on the

107
00:05:19.399 --> 00:05:22.160
<v Speaker 1>fly in some magical way. Instead, it compares the expression

108
00:05:22.199 --> 00:05:26.319
<v Speaker 1>tree against the library of translation patterns. It understands recognized

109
00:05:26.360 --> 00:05:29.879
<v Speaker 1>shapes in the tree map to escual templates. Unrecognized ones

110
00:05:29.959 --> 00:05:33.439
<v Speaker 1>either get deferred to client side execution or rejected, and

111
00:05:33.519 --> 00:05:36.720
<v Speaker 1>that's why some complex queries work fine, while others lead

112
00:05:36.720 --> 00:05:40.319
<v Speaker 1>to messages about unsupported translation. The decision is deterministic. It's

113
00:05:40.360 --> 00:05:43.399
<v Speaker 1>all about whether a given pattern has a known valid

114
00:05:43.680 --> 00:05:46.240
<v Speaker 1>sequel output, and this is also the stage where client

115
00:05:46.279 --> 00:05:48.879
<v Speaker 1>side evaluation shows up. If a part of the query

116
00:05:48.879 --> 00:05:51.120
<v Speaker 1>can't be turned into SQL YFCRE may still run it

117
00:05:51.120 --> 00:05:53.600
<v Speaker 1>in memory after fetching the data At first glance. That

118
00:05:53.600 --> 00:05:57.240
<v Speaker 1>seems practical. Sequel gives you the data net finishes the job,

119
00:05:57.279 --> 00:06:00.079
<v Speaker 1>but the cost can be huge if the database hands

120
00:06:00.079 --> 00:06:03.600
<v Speaker 1>over thousands or even millions of rows just so net

121
00:06:03.600 --> 00:06:06.759
<v Speaker 1>can filter them. Afterward performance collapses. Something that looked innocent

122
00:06:06.800 --> 00:06:09.279
<v Speaker 1>in a local test database can stall badly in production

123
00:06:09.319 --> 00:06:12.639
<v Speaker 1>when the data volume grows. Developers often underestimate the shift.

124
00:06:12.759 --> 00:06:15.560
<v Speaker 1>Think of a query that seems perfectly fine while developing

125
00:06:15.600 --> 00:06:18.199
<v Speaker 1>against a data set of a few hundred rows. In production,

126
00:06:18.319 --> 00:06:20.920
<v Speaker 1>the same query retrieves tens of thousands of records and

127
00:06:20.959 --> 00:06:23.839
<v Speaker 1>runs a slow operation on the application server. That's when

128
00:06:23.959 --> 00:06:27.519
<v Speaker 1>users start complaining that everything feels stuck. The provider's guardrails

129
00:06:27.560 --> 00:06:29.720
<v Speaker 1>matter here, and in many cases it's safer to get

130
00:06:29.759 --> 00:06:32.519
<v Speaker 1>an error than to let EF try to do something inefficient.

131
00:06:32.639 --> 00:06:35.519
<v Speaker 1>For anyone building with EF, the practical takeaway is simple.

132
00:06:35.800 --> 00:06:39.199
<v Speaker 1>Always test queries against real or representative data, and pay

133
00:06:39.240 --> 00:06:42.759
<v Speaker 1>attention to whether performance suddenly knows dives in production. If

134
00:06:42.759 --> 00:06:45.439
<v Speaker 1>it feels fast locally but drags underload, that's often as

135
00:06:45.480 --> 00:06:48.000
<v Speaker 1>sign the provider has pushed part of your logic to

136
00:06:48.199 --> 00:06:51.160
<v Speaker 1>client side. Evaluation is not automatically wrong, but it is

137
00:06:51.199 --> 00:06:53.720
<v Speaker 1>a signal you need to pay closer attention. So while

138
00:06:53.720 --> 00:06:56.040
<v Speaker 1>the provider is the gatekeeper, it isn't just standing guard.

139
00:06:56.120 --> 00:06:59.680
<v Speaker 1>It's protecting both correctness and performance by filtering what can

140
00:06:59.720 --> 00:07:02.639
<v Speaker 1>be te translated into SQL and controlling when to fall

141
00:07:02.639 --> 00:07:05.839
<v Speaker 1>back to client side execution. It keeps your pipeline predictable.

142
00:07:05.959 --> 00:07:08.079
<v Speaker 1>At the same time, it's under constant pressure to make

143
00:07:08.120 --> 00:07:11.839
<v Speaker 1>these decisions quickly without rewriting your query structure from scratch

144
00:07:11.879 --> 00:07:14.319
<v Speaker 1>every time. And that's where another piece of EF core's

145
00:07:14.360 --> 00:07:17.560
<v Speaker 1>design becomes essential. A system to remember and reuse decisions

146
00:07:17.639 --> 00:07:21.680
<v Speaker 1>rather than starting from zero on every request. Catching EF's

147
00:07:21.680 --> 00:07:26.079
<v Speaker 1>secret performance weapon, here's where performance stops being theoretical. Entity

148
00:07:26.079 --> 00:07:28.560
<v Speaker 1>Framework Core relies on caching as one of its biggest

149
00:07:28.560 --> 00:07:32.000
<v Speaker 1>performance tools, and without it, query translation would be painfully inefficient.

150
00:07:32.519 --> 00:07:35.040
<v Speaker 1>Every link query starts its life as an expression tree

151
00:07:35.040 --> 00:07:38.000
<v Speaker 1>and has to be analyzed, validated, and prepared for sickle translation.

152
00:07:38.199 --> 00:07:40.920
<v Speaker 1>Network isn't free if EF had to repeat it from

153
00:07:40.959 --> 00:07:44.279
<v Speaker 1>scratch on every execution. Even simple queries would bog down

154
00:07:44.319 --> 00:07:47.199
<v Speaker 1>once repeated frequently. To picture what that would mean in practice,

155
00:07:47.240 --> 00:07:49.800
<v Speaker 1>think about running the same query thousands of times per

156
00:07:49.839 --> 00:07:52.680
<v Speaker 1>second in a production app. Without caching. EF core would

157
00:07:52.680 --> 00:07:55.480
<v Speaker 1>grind through full passing and translation on each call. The

158
00:07:55.560 --> 00:07:58.279
<v Speaker 1>database wouldn't necessarily be the problem. Your CPU would spike

159
00:07:58.399 --> 00:08:00.920
<v Speaker 1>just from EF redoing the prep work. This is why

160
00:08:00.920 --> 00:08:03.920
<v Speaker 1>cachhing isn't an optional optimization, it's the foundation that makes

161
00:08:04.000 --> 00:08:06.560
<v Speaker 1>ef core workable at real world scale. So how does

162
00:08:06.600 --> 00:08:09.639
<v Speaker 1>it actually help? Efcre uses caching to recognize when a

163
00:08:09.680 --> 00:08:12.800
<v Speaker 1>query shape it has already processed shows up again. Instead

164
00:08:12.839 --> 00:08:15.480
<v Speaker 1>of reanalyzing the expression tree node by node, EF can

165
00:08:15.560 --> 00:08:18.040
<v Speaker 1>reuse the earlier work, and that means when you filter

166
00:08:18.120 --> 00:08:21.120
<v Speaker 1>by something like customer eyed, the first run takes longer

167
00:08:21.160 --> 00:08:23.720
<v Speaker 1>while EF figures out how to map that filter into SQL.

168
00:08:23.920 --> 00:08:27.199
<v Speaker 1>After that, subsequent executions with different parameter values are fast

169
00:08:27.240 --> 00:08:29.839
<v Speaker 1>because the heavy lifting has already been stored in short

170
00:08:29.920 --> 00:08:33.519
<v Speaker 1>first pass builds. The plan later passes reuse it now.

171
00:08:33.600 --> 00:08:36.360
<v Speaker 1>The details of exactly how this cache is structured vary

172
00:08:36.399 --> 00:08:39.320
<v Speaker 1>by ef core version and provider, but the general principle

173
00:08:39.360 --> 00:08:42.399
<v Speaker 1>is consistent. The cash keeps track of repeated query shapes.

174
00:08:42.759 --> 00:08:45.120
<v Speaker 1>When the model changes, say you add a property to

175
00:08:45.159 --> 00:08:47.320
<v Speaker 1>an entity, the cased items are no longer valid and

176
00:08:47.399 --> 00:08:50.879
<v Speaker 1>EF clears them. This prevents mismatched SQL from ever being reused.

177
00:08:51.200 --> 00:08:54.519
<v Speaker 1>The implementation specifics, such as multiple caching layers or eviction

178
00:08:54.679 --> 00:08:58.000
<v Speaker 1>rules are tied to version and configuration details and should

179
00:08:58.039 --> 00:09:01.879
<v Speaker 1>be checked in official ef core documentation From a developer's perspective,

180
00:09:01.919 --> 00:09:05.120
<v Speaker 1>the result is straightforward. Queries run noticeably faster after the

181
00:09:05.120 --> 00:09:08.279
<v Speaker 1>first execution. That's caching at work. The benefit is easy

182
00:09:08.279 --> 00:09:11.559
<v Speaker 1>to underestimate because the speed increase feels invisible until you

183
00:09:11.600 --> 00:09:14.360
<v Speaker 1>turn cashing off or hit a pattern that doesn't reuse

184
00:09:14.399 --> 00:09:17.159
<v Speaker 1>as efficiently. Once you realize what it's doing, you start

185
00:09:17.159 --> 00:09:19.200
<v Speaker 1>to see why EF can stay response if even under

186
00:09:19.240 --> 00:09:21.720
<v Speaker 1>heavy load. But cashing is not a free ride. Every

187
00:09:21.759 --> 00:09:24.440
<v Speaker 1>cash entry takes memory, and applications with a high number

188
00:09:24.480 --> 00:09:27.559
<v Speaker 1>of unique query shapes can see memory usage climb. If

189
00:09:27.559 --> 00:09:31.159
<v Speaker 1>you rely heavily on dynamically composed queries. String building predicates

190
00:09:31.240 --> 00:09:34.559
<v Speaker 1>run time generated projections or code that produces slightly different

191
00:09:34.559 --> 00:09:37.960
<v Speaker 1>shapes every call, you'll generate many cash entries that never

192
00:09:38.000 --> 00:09:41.080
<v Speaker 1>get reused. That's when the cash becomes a liability instead

193
00:09:41.080 --> 00:09:43.080
<v Speaker 1>of an asset. Developers should keep an eye out for

194
00:09:43.120 --> 00:09:46.120
<v Speaker 1>that pattern. Fewer, more consistent query shapes make the most

195
00:09:46.120 --> 00:09:48.919
<v Speaker 1>of caching and avoid wasting memory. The trick for teams

196
00:09:48.919 --> 00:09:51.799
<v Speaker 1>is recognizing that cased queries are both a performance advantage

197
00:09:51.840 --> 00:09:54.440
<v Speaker 1>and a potential memory cost. You want to take advantage

198
00:09:54.440 --> 00:09:56.919
<v Speaker 1>of caching on repetitive work queries you know will run

199
00:09:56.919 --> 00:09:59.600
<v Speaker 1>thousands of times, but be aware of how your application

200
00:09:59.639 --> 00:10:03.000
<v Speaker 1>builds queries. If you're generating too many unique ones, the

201
00:10:03.080 --> 00:10:05.200
<v Speaker 1>cash has to hold onto shapes that are unlikely to

202
00:10:05.240 --> 00:10:08.600
<v Speaker 1>be seen again. That can add unexpected weight to your system,

203
00:10:08.679 --> 00:10:11.799
<v Speaker 1>especially at scale. In practice, the best advice is to

204
00:10:11.879 --> 00:10:15.840
<v Speaker 1>let ef core handle caching automatically, but to be intentional

205
00:10:15.879 --> 00:10:18.600
<v Speaker 1>about how you write queries. If you notice memory pressure

206
00:10:18.639 --> 00:10:21.639
<v Speaker 1>in your application, while databaseload looks normal, consider whether the

207
00:10:21.679 --> 00:10:24.240
<v Speaker 1>issue might be related to lots of cached query shapes.

208
00:10:24.559 --> 00:10:26.720
<v Speaker 1>It's not the first place developers look, but it's often

209
00:10:26.759 --> 00:10:30.240
<v Speaker 1>a silent contributor. Optimizing query patterns can be as important

210
00:10:30.279 --> 00:10:33.919
<v Speaker 1>as optimizing the database itself. Cashing often explains why ef

211
00:10:33.960 --> 00:10:37.039
<v Speaker 1>queries feel fast after that initial delay. It's doing the

212
00:10:37.080 --> 00:10:39.919
<v Speaker 1>same job once, then skipping overhead on repeats. Simple but

213
00:10:40.039 --> 00:10:43.799
<v Speaker 1>powerful still even when query execution feels smooth. Another source

214
00:10:43.799 --> 00:10:47.120
<v Speaker 1>of subtle bugs lurks just around the corner handling null values.

215
00:10:47.200 --> 00:10:49.600
<v Speaker 1>That's where ef core has to bridge two very different

216
00:10:49.639 --> 00:10:52.679
<v Speaker 1>definitions of nothing, and it's a problem developers run into

217
00:10:52.720 --> 00:10:57.039
<v Speaker 1>early time null semantics when nothing means different things. In

218
00:10:57.080 --> 00:11:00.960
<v Speaker 1>most everyday coding developers can treat null as a simple concept,

219
00:11:01.120 --> 00:11:03.960
<v Speaker 1>but the reality is more complicated once ef core sits

220
00:11:04.000 --> 00:11:06.960
<v Speaker 1>between c BOSS and a SQL database. This is where

221
00:11:06.960 --> 00:11:09.720
<v Speaker 1>the issue of null semantics takes center stage. The rules

222
00:11:09.759 --> 00:11:12.919
<v Speaker 1>you think you're applying in NET don't always mean the

223
00:11:12.960 --> 00:11:16.279
<v Speaker 1>same thing when the database evaluates them. In CR, null

224
00:11:16.320 --> 00:11:19.720
<v Speaker 1>is straightforward a missing object reference, an unassigned string, a

225
00:11:19.759 --> 00:11:22.240
<v Speaker 1>property that hasn't been set all amount to the same thing.

226
00:11:22.559 --> 00:11:25.080
<v Speaker 1>But CQL operates differently. It doesn't use null in a

227
00:11:25.080 --> 00:11:28.480
<v Speaker 1>way that lines up directly with NT. SQL treats it

228
00:11:28.519 --> 00:11:31.279
<v Speaker 1>more like an unknown value, which affects how comparisons behave.

229
00:11:31.679 --> 00:11:34.240
<v Speaker 1>For instance, in SQL, writing column in null will not

230
00:11:34.320 --> 00:11:37.360
<v Speaker 1>behave like a true false test. Instead, it produces special

231
00:11:37.360 --> 00:11:40.320
<v Speaker 1>handling that requires is null checks. This is a critical

232
00:11:40.360 --> 00:11:43.159
<v Speaker 1>distinction developers need to keep in mind. A quick example

233
00:11:43.159 --> 00:11:46.799
<v Speaker 1>makes the difference clear. Suppose you write for query customers

234
00:11:47.120 --> 00:11:50.440
<v Speaker 1>where c Klow's c name exus null. Run that query

235
00:11:50.480 --> 00:11:52.919
<v Speaker 1>in memory against the list of customer objects, and you'll

236
00:11:52.919 --> 00:11:56.240
<v Speaker 1>reliably get back those whose name is actually null. Translate

237
00:11:56.240 --> 00:11:59.440
<v Speaker 1>that same logic into SQL without adjustments, and you'd expect

238
00:11:59.440 --> 00:12:01.919
<v Speaker 1>to see where no name ix null in practice, that

239
00:12:01.960 --> 00:12:04.639
<v Speaker 1>would not return any rows at all. The correct circle

240
00:12:04.720 --> 00:12:07.600
<v Speaker 1>form would be where name is null. Being mindful of

241
00:12:07.600 --> 00:12:10.080
<v Speaker 1>the difference matters. As a developer. It's a good habit

242
00:12:10.120 --> 00:12:12.200
<v Speaker 1>to check the circle output when your link you depends

243
00:12:12.240 --> 00:12:15.399
<v Speaker 1>on null comparisons, especially to avoid surprises when moving to

244
00:12:15.440 --> 00:12:18.080
<v Speaker 1>production data. This mismatch is at the root of why

245
00:12:18.200 --> 00:12:21.720
<v Speaker 1>null queries sometimes behave so strangely in ef core. If

246
00:12:21.799 --> 00:12:24.919
<v Speaker 1>left uncorrected, something that seems predictable in cpars could silently

247
00:12:24.960 --> 00:12:27.639
<v Speaker 1>yield no results in the database. Occasionally, it might even

248
00:12:27.679 --> 00:12:29.879
<v Speaker 1>give results that look fine in small tests but fail

249
00:12:29.919 --> 00:12:32.720
<v Speaker 1>in real scenarios where nulls appear more often, that's an

250
00:12:32.759 --> 00:12:35.120
<v Speaker 1>easy way for subtle bugs to sneak in without warning.

251
00:12:35.519 --> 00:12:37.879
<v Speaker 1>To reduce this risk, ef core doesn't simply pass your

252
00:12:37.960 --> 00:12:41.399
<v Speaker 1>null comparisons through. Instead, it applies rules to keep net

253
00:12:41.440 --> 00:12:44.919
<v Speaker 1>and ccle behavior aligned. For equality checks, ef will usually

254
00:12:44.960 --> 00:12:48.279
<v Speaker 1>adjust them into is null or is not null conditions.

255
00:12:48.879 --> 00:12:52.840
<v Speaker 1>For more involved predicates, the pipeline often performs compensating transformations

256
00:12:53.159 --> 00:12:55.679
<v Speaker 1>so database results stay in sync with what a NEET

257
00:12:55.799 --> 00:12:58.879
<v Speaker 1>runtime logic would have done. The exact internals of these

258
00:12:58.879 --> 00:13:01.960
<v Speaker 1>adjustments depend on vers and provider, but The guiding principle

259
00:13:02.080 --> 00:13:06.919
<v Speaker 1>is consistent preserve developer expectations by normalizing null logic. However,

260
00:13:06.960 --> 00:13:10.039
<v Speaker 1>this alignment comes at a cost. Those compensating transformations can

261
00:13:10.080 --> 00:13:12.440
<v Speaker 1>make SEQL queries longer and more complex than what it

262
00:13:12.440 --> 00:13:16.279
<v Speaker 1>seemed you wrote. EF is prioritizing correctness over simplicity, sometimes

263
00:13:16.279 --> 00:13:19.000
<v Speaker 1>at the expense of efficiency. That's why you may occasionally

264
00:13:19.000 --> 00:13:22.279
<v Speaker 1>see generated sequel with extra conditions that don't match your

265
00:13:22.320 --> 00:13:26.320
<v Speaker 1>clean link statement. It's EF quietly ensuring you don't wake

266
00:13:26.399 --> 00:13:29.840
<v Speaker 1>up to inconsistent results later. The complexity of the generated

267
00:13:29.960 --> 00:13:32.799
<v Speaker 1>query is often the visible side effect of keeping null

268
00:13:32.879 --> 00:13:37.320
<v Speaker 1>semantics safe across two systems with conflicting definitions. What matters

269
00:13:37.320 --> 00:13:40.399
<v Speaker 1>most for developers is recognizing the potential risk in null handling.

270
00:13:40.840 --> 00:13:44.480
<v Speaker 1>If a query appears odd, slow, or overly complex, null

271
00:13:44.559 --> 00:13:47.320
<v Speaker 1>checks are a good place to start troubleshooting. A short

272
00:13:47.360 --> 00:13:50.360
<v Speaker 1>but practical takeaway is this, if a query involving nulls

273
00:13:50.440 --> 00:13:54.279
<v Speaker 1>behaves oddly, check for translation differences or hidden rewrites. These

274
00:13:54.320 --> 00:13:57.360
<v Speaker 1>are not mistakes so much as protective guardrails ef core

275
00:13:57.399 --> 00:14:00.320
<v Speaker 1>has built in. The Real danger is assuming high harmless

276
00:14:00.399 --> 00:14:03.080
<v Speaker 1>null checks behave the same in both environments. They don't,

277
00:14:03.240 --> 00:14:05.440
<v Speaker 1>and that can surface as bugs that only appear with

278
00:14:05.519 --> 00:14:08.679
<v Speaker 1>production data not in a tidy test set. For example,

279
00:14:08.720 --> 00:14:11.480
<v Speaker 1>you might think a filter excludes nulls until you notice

280
00:14:11.480 --> 00:14:15.000
<v Speaker 1>certain records mysteriously missing. That kind of silent mismatch can

281
00:14:15.039 --> 00:14:17.639
<v Speaker 1>be one of the hardest issues to track down unless

282
00:14:17.679 --> 00:14:21.080
<v Speaker 1>you've validated the generated sequel against real data volumes and patterns.

283
00:14:21.399 --> 00:14:24.200
<v Speaker 1>So while null semantics are a headache, they also represent

284
00:14:24.240 --> 00:14:27.639
<v Speaker 1>one of ef core's most important interventions. By compensating for

285
00:14:27.639 --> 00:14:30.960
<v Speaker 1>the mismatch, EF helps smooth over a gap that could

286
00:14:30.960 --> 00:14:34.759
<v Speaker 1>otherwise cause unpredictable failures. Developers may not like the extra

287
00:14:34.799 --> 00:14:37.200
<v Speaker 1>circle that shows up in the process, but without it,

288
00:14:37.240 --> 00:14:40.279
<v Speaker 1>the results would be unreliable. Having dealt with nulls, EF

289
00:14:40.320 --> 00:14:42.720
<v Speaker 1>is now carrying a query that's been passed, filtered through

290
00:14:42.720 --> 00:14:46.000
<v Speaker 1>the provider, cashed, and adjusted to keep logic consistent. The

291
00:14:46.039 --> 00:14:48.720
<v Speaker 1>final question is what happens next. How does this prepared

292
00:14:48.799 --> 00:14:52.159
<v Speaker 1>query become a circle command that the database can actually execute,

293
00:14:52.360 --> 00:14:54.639
<v Speaker 1>and how is the raw data turned back into usable

294
00:14:55.679 --> 00:14:59.480
<v Speaker 1>and net objects For ess seqle generation and materialization, the

295
00:14:59.559 --> 00:15:02.600
<v Speaker 1>last state of the pipeline is sequel generation and materialization,

296
00:15:02.759 --> 00:15:05.240
<v Speaker 1>the point where all that preparation either pays off or

297
00:15:05.320 --> 00:15:08.559
<v Speaker 1>falls apart. Everything up to now has been about shaping intent,

298
00:15:08.879 --> 00:15:12.799
<v Speaker 1>validating patterns, and protecting consistency. But queries only become useful

299
00:15:12.799 --> 00:15:15.320
<v Speaker 1>when efcor can turn that intent into a circle command

300
00:15:15.440 --> 00:15:19.000
<v Speaker 1>your database understands, and then reshape the flat results into

301
00:15:19.080 --> 00:15:22.360
<v Speaker 1>rich objects. Your code can actually work with two moving

302
00:15:22.399 --> 00:15:24.799
<v Speaker 1>parts to the bulk of this work, the seqle generator

303
00:15:24.799 --> 00:15:28.200
<v Speaker 1>and the materializer. They solve opposite problems but depend on

304
00:15:28.240 --> 00:15:32.039
<v Speaker 1>each other. SEQLE generation is provider aware. Provider components influence

305
00:15:32.080 --> 00:15:35.559
<v Speaker 1>how queries are expressed for a given database dialect. Materialization

306
00:15:35.639 --> 00:15:38.000
<v Speaker 1>then takes the rows that come back and builds entities

307
00:15:38.039 --> 00:15:41.240
<v Speaker 1>and projections into rsionnet. Neither side on its own is enough.

308
00:15:41.480 --> 00:15:45.360
<v Speaker 1>SECLE generation ensures the database can run the query. Materialization

309
00:15:45.519 --> 00:15:48.679
<v Speaker 1>ensures the results make sense for your application. That back

310
00:15:48.720 --> 00:15:51.000
<v Speaker 1>and forth is why this stage feels like translation in

311
00:15:51.039 --> 00:15:54.440
<v Speaker 1>two directions. A link filter that looked harmless in C

312
00:15:54.639 --> 00:15:57.759
<v Speaker 1>parts needs to be written as valid sequel for postgress,

313
00:15:57.759 --> 00:16:01.080
<v Speaker 1>equal sequel server, or whichever provider you using. When the

314
00:16:01.159 --> 00:16:04.639
<v Speaker 1>database replies, ef receives nothing more than rows and columns,

315
00:16:04.639 --> 00:16:07.159
<v Speaker 1>which it cannot simply hand to you without context. Your

316
00:16:07.200 --> 00:16:10.879
<v Speaker 1>expectation is that you'll receive entities with navigation properties, wired up,

317
00:16:10.960 --> 00:16:14.559
<v Speaker 1>typed values in the right places and relationships intact. Bridging

318
00:16:14.559 --> 00:16:16.320
<v Speaker 1>that gap is what these steps are designed to do.

319
00:16:16.519 --> 00:16:18.639
<v Speaker 1>Think about it with a simple example. If you've written

320
00:16:18.679 --> 00:16:21.759
<v Speaker 1>a query that includes related entities, say an order with

321
00:16:21.879 --> 00:16:23.799
<v Speaker 1>its order lines, you don't want to see half a

322
00:16:23.799 --> 00:16:26.960
<v Speaker 1>dozen partial rows and stitch them together Manually. You expect

323
00:16:26.960 --> 00:16:29.639
<v Speaker 1>to see an order object that contains a populated order

324
00:16:29.679 --> 00:16:34.480
<v Speaker 1>lines collection. That's materialization in action. EF reconstructs a full

325
00:16:34.559 --> 00:16:37.399
<v Speaker 1>object graph from sets of rows, and here's a practical pointer.

326
00:16:37.559 --> 00:16:41.080
<v Speaker 1>If you're noticing duplicate tracked objects or missing navigation values,

327
00:16:41.080 --> 00:16:43.399
<v Speaker 1>it often comes down to how those joints were shaped

328
00:16:43.440 --> 00:16:47.960
<v Speaker 1>and how EF materialized the results. Sickle generation itself highlights

329
00:16:48.000 --> 00:16:51.080
<v Speaker 1>EF's dependency on providers. The framework doesn't attempt to hard

330
00:16:51.080 --> 00:16:54.759
<v Speaker 1>code every syntax detail. Instead, providers supply the logic for

331
00:16:54.799 --> 00:16:58.320
<v Speaker 1>their database. That means the same ali ink query might

332
00:16:58.440 --> 00:17:02.399
<v Speaker 1>render slightly different sequels in different environments. Brackets might appear

333
00:17:02.440 --> 00:17:05.880
<v Speaker 1>on CQL server, quoted identifiers on postgresscool, different type co

334
00:17:06.000 --> 00:17:08.960
<v Speaker 1>versions elsewhere. These variations matter because they determine whether the

335
00:17:09.039 --> 00:17:12.759
<v Speaker 1>query is actually valid for the target database. This principle

336
00:17:12.839 --> 00:17:15.160
<v Speaker 1>is worth confirming against the EF core docs for the

337
00:17:15.200 --> 00:17:18.759
<v Speaker 1>specific version and provider you're using. Since capabilities evolve on

338
00:17:18.799 --> 00:17:21.359
<v Speaker 1>the materialization side, EF has to handle more than just

339
00:17:21.440 --> 00:17:24.640
<v Speaker 1>simple mappings. It needs to line up database column types

340
00:17:24.680 --> 00:17:27.920
<v Speaker 1>with net types, enforce conversion when needed, and fix up

341
00:17:27.920 --> 00:17:31.799
<v Speaker 1>foreign keys so relationships turn into real object references. Projections.

342
00:17:31.799 --> 00:17:34.400
<v Speaker 1>Add another twist, A query that asks for a custom

343
00:17:34.440 --> 00:17:36.920
<v Speaker 1>dto or an anonymous type must be assembled directly from

344
00:17:36.960 --> 00:17:39.240
<v Speaker 1>the results set without ever creating a full entity. That

345
00:17:39.319 --> 00:17:42.599
<v Speaker 1>flexibility is where developers feel EF adapting to their needs,

346
00:17:42.920 --> 00:17:45.839
<v Speaker 1>but it adds real complexity to the engine underneath. There

347
00:17:45.880 --> 00:17:49.200
<v Speaker 1>are also cases where the materializer tracks properties you didn't

348
00:17:49.279 --> 00:17:53.359
<v Speaker 1>explicitly define. Features like shadow properties or lazy loading hooks

349
00:17:53.400 --> 00:17:56.279
<v Speaker 1>fit here, but these vary by EF core, version and provider,

350
00:17:56.440 --> 00:17:59.799
<v Speaker 1>so check the documentation of your target environment before relying

351
00:17:59.839 --> 00:18:03.039
<v Speaker 1>on them. What matters most is that materialization manages to

352
00:18:03.119 --> 00:18:06.400
<v Speaker 1>hide this entire process. Developers see a clean object model,

353
00:18:06.440 --> 00:18:10.880
<v Speaker 1>while EF has spent considerable effort balancing performance with correctness relationships,

354
00:18:10.880 --> 00:18:13.599
<v Speaker 1>give a good snapshot of the hidden work involved. Instead

355
00:18:13.640 --> 00:18:15.839
<v Speaker 1>of handing you rows that reference each other by id,

356
00:18:15.960 --> 00:18:19.759
<v Speaker 1>EF resolves those references into navigation properties. The tip here

357
00:18:19.799 --> 00:18:23.799
<v Speaker 1>is simple. If navigation properties are empty or inconsistent, revisiting

358
00:18:23.839 --> 00:18:27.359
<v Speaker 1>how you shape the query, especially with include or projection choices,

359
00:18:27.759 --> 00:18:31.000
<v Speaker 1>can often resolve it. So in practice, secle, generation and

360
00:18:31.039 --> 00:18:34.359
<v Speaker 1>materialization give EF its most visible impact. These are the

361
00:18:34.359 --> 00:18:37.720
<v Speaker 1>stages that make the difference between a developer friendly experience

362
00:18:37.720 --> 00:18:41.000
<v Speaker 1>and data plumbing that would otherwise consume hours of manual mapping.

363
00:18:41.400 --> 00:18:43.599
<v Speaker 1>When you query with EF, you get back something that

364
00:18:43.640 --> 00:18:47.359
<v Speaker 1>feels natural in net, not because seql gave you objects,

365
00:18:47.359 --> 00:18:49.920
<v Speaker 1>but because EF rebuild them that way. This is why

366
00:18:49.960 --> 00:18:53.079
<v Speaker 1>the process often feels like magic. Two different engines, one

367
00:18:53.160 --> 00:18:56.359
<v Speaker 1>fluent in database dialects, the other fluent in and net

368
00:18:56.400 --> 00:18:58.960
<v Speaker 1>objects hand off work seamlessly so you see only the

369
00:18:58.960 --> 00:19:01.480
<v Speaker 1>finished result. But it isn't magic at all. It's a

370
00:19:01.480 --> 00:19:05.559
<v Speaker 1>pipeline deliberately layered to keep performance, correctness, and usability in balance.

371
00:19:05.720 --> 00:19:08.880
<v Speaker 1>And that careful layering is the real story behind Entity Framework,

372
00:19:09.039 --> 00:19:11.680
<v Speaker 1>or what holds EF core together. Isn't magic, but a

373
00:19:11.759 --> 00:19:16.359
<v Speaker 1>chain of deliberate steps. Expression trees, query providers, caching, null handling,

374
00:19:16.400 --> 00:19:19.880
<v Speaker 1>and materialization, all shaping how your queries perform and behave.

375
00:19:20.319 --> 00:19:22.640
<v Speaker 1>Knowing these moving pieces makes a difference, because a query

376
00:19:22.640 --> 00:19:25.200
<v Speaker 1>that seems harmless in code can perform very differently. Under

377
00:19:25.240 --> 00:19:27.680
<v Speaker 1>Load as practical next steps, keep three things in mind.

378
00:19:27.759 --> 00:19:30.400
<v Speaker 1>Check generated skill for complex expressions, watch for signs of

379
00:19:30.480 --> 00:19:34.000
<v Speaker 1>client side evaluation, and monitor how diverse your query shapes

380
00:19:34.000 --> 00:19:38.400
<v Speaker 1>are to avoid unnecessary cash growth. Looking ahead, it's worth asking,

381
00:19:38.559 --> 00:19:42.119
<v Speaker 1>as AI driven developer tools spread, could caching, null handling

382
00:19:42.240 --> 00:19:45.400
<v Speaker 1>or ceqle translation be reimagined and what would it mean

383
00:19:45.440 --> 00:19:48.759
<v Speaker 1>for frameworks like ef core. Share your own toughest query

384
00:19:48.799 --> 00:19:51.440
<v Speaker 1>translation issues in the comments, and don't forget to like

385
00:19:51.480 --> 00:19:54.519
<v Speaker 1>and subscribe. Understanding this pipeline is not just academic. It's

386
00:19:54.599 --> 00:19:57.319
<v Speaker 1>essential for keeping your applications reliable and responsive.
