[{"data":1,"prerenderedAt":1280},["ShallowReactive",2],{"blog-\u002Fblog\u002Fdotnet-linq-deferred-execution-iqueryable":3},{"id":4,"title":5,"body":6,"description":1265,"difficulty":1266,"extension":1267,"framework":1268,"frameworkSlug":1269,"meta":1270,"navigation":133,"order":143,"path":1271,"qaPath":1272,"seo":1273,"stem":1274,"subtopic":1275,"topic":1276,"topicSlug":1277,"updated":1278,"__hash__":1279},"blog\u002Fblog\u002Fdotnet-linq-deferred-execution-iqueryable.md","How LINQ Works in C#: Deferred Execution and IQueryable",{"type":7,"value":8,"toc":1242},"minimark",[9,14,18,22,29,90,104,108,111,206,220,226,230,242,289,296,348,353,358,406,411,441,446,486,500,504,507,561,582,632,636,640,649,727,736,740,783,793,796,808,876,899,903,980,984,1037,1041,1045,1089,1100,1129,1133,1180,1184,1238],[10,11,13],"h2",{"id":12},"why-linq-proficiency-separates-good-c-developers-from-great-ones","Why LINQ proficiency separates good C# developers from great ones",[15,16,17],"p",{},"LINQ is one of the most distinctive features of C# — a declarative query model baked\ninto the language itself. Used well, it makes code significantly more readable and\nconcise. Used poorly, it is a source of N+1 database queries, hidden performance costs,\nand subtle bugs caused by deferred execution. Interviews probe both sides: can you write\ncorrect LINQ, and can you identify where it goes wrong?",[10,19,21],{"id":20},"what-linq-is-and-isnt","What LINQ is (and isn't)",[15,23,24,28],{},[25,26,27],"strong",{},"LINQ (Language Integrated Query)"," is three things working together:",[30,31,32,48,81],"ol",{},[33,34,35,38,39,43,44,47],"li",{},[25,36,37],{},"Language features"," — query syntax (",[40,41,42],"code",{},"from x in xs where … select …","), the ",[40,45,46],{},"yield","\nmachinery powering iterators, and lambda expression support.",[33,49,50,53,54,57,58,57,61,64,65,68,69,72,73,76,77,80],{},[25,51,52],{},"Extension methods"," — ",[40,55,56],{},"Where",", ",[40,59,60],{},"Select",[40,62,63],{},"GroupBy",", etc. defined on\n",[40,66,67],{},"IEnumerable\u003CT>"," in ",[40,70,71],{},"System.Linq.Enumerable"," and on ",[40,74,75],{},"IQueryable\u003CT>"," in\n",[40,78,79],{},"System.Linq.Queryable",".",[33,82,83,86,87,89],{},[25,84,85],{},"Provider model"," — any data source can expose ",[40,88,75],{}," and provide a\nLINQ provider that translates expression trees to native queries. EF Core translates\nto SQL; LINQ to XML to XPath; custom providers to anything.",[15,91,92,93,96,97,99,100,103],{},"LINQ is ",[25,94,95],{},"not"," magic and is ",[25,98,95],{}," always the right tool. For a simple loop over a\nsmall local list, a ",[40,101,102],{},"foreach"," is often clearer and equally fast. Reach for LINQ when\nthe declarative composition adds clarity or when the query involves filtering, grouping,\nprojecting, or joining.",[10,105,107],{"id":106},"query-syntax-vs-method-syntax-they-are-identical","Query syntax vs method syntax — they are identical",[15,109,110],{},"Both syntaxes compile to the same method calls. The compiler translates query syntax\ninto method syntax before emitting IL.",[112,113,118],"pre",{"className":114,"code":115,"language":116,"meta":117,"style":117},"language-csharp shiki shiki-themes github-light github-dark","int[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n\n\u002F\u002F Query syntax:\nvar q1 = from n in data\n         where n % 2 == 0\n         orderby n descending\n         select n * n;\n\n\u002F\u002F Method (fluent) syntax — identical IL after compilation:\nvar q2 = data\n    .Where(n => n % 2 == 0)\n    .OrderByDescending(n => n)\n    .Select(n => n * n);\n\u002F\u002F Both: 100, 64, 36, 16, 4\n","csharp","",[40,119,120,128,135,141,147,153,159,165,170,176,182,188,194,200],{"__ignoreMap":117},[121,122,125],"span",{"class":123,"line":124},"line",1,[121,126,127],{},"int[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n",[121,129,131],{"class":123,"line":130},2,[121,132,134],{"emptyLinePlaceholder":133},true,"\n",[121,136,138],{"class":123,"line":137},3,[121,139,140],{},"\u002F\u002F Query syntax:\n",[121,142,144],{"class":123,"line":143},4,[121,145,146],{},"var q1 = from n in data\n",[121,148,150],{"class":123,"line":149},5,[121,151,152],{},"         where n % 2 == 0\n",[121,154,156],{"class":123,"line":155},6,[121,157,158],{},"         orderby n descending\n",[121,160,162],{"class":123,"line":161},7,[121,163,164],{},"         select n * n;\n",[121,166,168],{"class":123,"line":167},8,[121,169,134],{"emptyLinePlaceholder":133},[121,171,173],{"class":123,"line":172},9,[121,174,175],{},"\u002F\u002F Method (fluent) syntax — identical IL after compilation:\n",[121,177,179],{"class":123,"line":178},10,[121,180,181],{},"var q2 = data\n",[121,183,185],{"class":123,"line":184},11,[121,186,187],{},"    .Where(n => n % 2 == 0)\n",[121,189,191],{"class":123,"line":190},12,[121,192,193],{},"    .OrderByDescending(n => n)\n",[121,195,197],{"class":123,"line":196},13,[121,198,199],{},"    .Select(n => n * n);\n",[121,201,203],{"class":123,"line":202},14,[121,204,205],{},"\u002F\u002F Both: 100, 64, 36, 16, 4\n",[15,207,208,211,212,215,216,219],{},[25,209,210],{},"When to prefer query syntax:"," complex multi-source joins, ",[40,213,214],{},"let"," clauses (intermediate\nvariables), and ",[40,217,218],{},"group … by … into"," grouping — these have cleaner expression in the SQL-like\nform.",[15,221,222,225],{},[25,223,224],{},"When to prefer method syntax:"," everything else. It covers every operator (many have no\nquery-syntax equivalent), chains naturally with other method calls, and is what most\n.NET codebases use.",[10,227,229],{"id":228},"deferred-execution-the-most-important-linq-concept","Deferred execution — the most important LINQ concept",[15,231,232,233,236,237,241],{},"The defining characteristic of LINQ is ",[25,234,235],{},"deferred execution",": a LINQ query is a\ndescription of ",[238,239,240],"em",{},"how to compute data",", not the data itself. The computation happens only\nwhen you iterate the result.",[112,243,245],{"className":114,"code":244,"language":116,"meta":117,"style":117},"var numbers = new List\u003Cint> { 1, 2, 3 };\n\n\u002F\u002F Defining the query — no iteration yet:\nvar query = numbers.Where(n => n > 1); \u002F\u002F IEnumerable\u003Cint>\n\nnumbers.Add(10); \u002F\u002F source modified after query defined\n\nforeach (var n in query)\n    Console.Write(n + \" \"); \u002F\u002F 2 3 10 — sees the added element!\n",[40,246,247,252,256,261,266,270,275,279,284],{"__ignoreMap":117},[121,248,249],{"class":123,"line":124},[121,250,251],{},"var numbers = new List\u003Cint> { 1, 2, 3 };\n",[121,253,254],{"class":123,"line":130},[121,255,134],{"emptyLinePlaceholder":133},[121,257,258],{"class":123,"line":137},[121,259,260],{},"\u002F\u002F Defining the query — no iteration yet:\n",[121,262,263],{"class":123,"line":143},[121,264,265],{},"var query = numbers.Where(n => n > 1); \u002F\u002F IEnumerable\u003Cint>\n",[121,267,268],{"class":123,"line":149},[121,269,134],{"emptyLinePlaceholder":133},[121,271,272],{"class":123,"line":155},[121,273,274],{},"numbers.Add(10); \u002F\u002F source modified after query defined\n",[121,276,277],{"class":123,"line":161},[121,278,134],{"emptyLinePlaceholder":133},[121,280,281],{"class":123,"line":167},[121,282,283],{},"foreach (var n in query)\n",[121,285,286],{"class":123,"line":172},[121,287,288],{},"    Console.Write(n + \" \"); \u002F\u002F 2 3 10 — sees the added element!\n",[15,290,291,292,295],{},"This is useful for ",[25,293,294],{},"query composition"," — you can build a pipeline incrementally and\nthe source is touched only once when you iterate:",[112,297,299],{"className":114,"code":298,"language":116,"meta":117,"style":117},"IQueryable\u003CProduct> q = db.Products\n    .Where(p => p.IsActive);\n\nif (filterCategory)\n    q = q.Where(p => p.Category == category);    \u002F\u002F add another condition\n\nif (sortByPrice)\n    q = q.OrderBy(p => p.Price);                 \u002F\u002F add ordering\n\nvar results = await q.ToListAsync();             \u002F\u002F ONE SQL with all conditions\n",[40,300,301,306,311,315,320,325,329,334,339,343],{"__ignoreMap":117},[121,302,303],{"class":123,"line":124},[121,304,305],{},"IQueryable\u003CProduct> q = db.Products\n",[121,307,308],{"class":123,"line":130},[121,309,310],{},"    .Where(p => p.IsActive);\n",[121,312,313],{"class":123,"line":137},[121,314,134],{"emptyLinePlaceholder":133},[121,316,317],{"class":123,"line":143},[121,318,319],{},"if (filterCategory)\n",[121,321,322],{"class":123,"line":149},[121,323,324],{},"    q = q.Where(p => p.Category == category);    \u002F\u002F add another condition\n",[121,326,327],{"class":123,"line":155},[121,328,134],{"emptyLinePlaceholder":133},[121,330,331],{"class":123,"line":161},[121,332,333],{},"if (sortByPrice)\n",[121,335,336],{"class":123,"line":167},[121,337,338],{},"    q = q.OrderBy(p => p.Price);                 \u002F\u002F add ordering\n",[121,340,341],{"class":123,"line":172},[121,342,134],{"emptyLinePlaceholder":133},[121,344,345],{"class":123,"line":178},[121,346,347],{},"var results = await q.ToListAsync();             \u002F\u002F ONE SQL with all conditions\n",[349,350,352],"h3",{"id":351},"when-deferred-execution-bites-you","When deferred execution bites you",[15,354,355],{},[25,356,357],{},"Multiple enumeration:",[112,359,361],{"className":114,"code":360,"language":116,"meta":117,"style":117},"IEnumerable\u003CUser> users = db.Users.Where(u => u.IsActive); \u002F\u002F deferred\n\nint count  = users.Count();  \u002F\u002F hits the DB — query runs once\nvar first  = users.First();  \u002F\u002F hits the DB — query runs again!\n\n\u002F\u002F Fix: materialise once\nvar cached = users.ToList();\nint count2  = cached.Count;   \u002F\u002F in-memory — no DB hit\nvar first2  = cached.First(); \u002F\u002F in-memory\n",[40,362,363,368,372,377,382,386,391,396,401],{"__ignoreMap":117},[121,364,365],{"class":123,"line":124},[121,366,367],{},"IEnumerable\u003CUser> users = db.Users.Where(u => u.IsActive); \u002F\u002F deferred\n",[121,369,370],{"class":123,"line":130},[121,371,134],{"emptyLinePlaceholder":133},[121,373,374],{"class":123,"line":137},[121,375,376],{},"int count  = users.Count();  \u002F\u002F hits the DB — query runs once\n",[121,378,379],{"class":123,"line":143},[121,380,381],{},"var first  = users.First();  \u002F\u002F hits the DB — query runs again!\n",[121,383,384],{"class":123,"line":149},[121,385,134],{"emptyLinePlaceholder":133},[121,387,388],{"class":123,"line":155},[121,389,390],{},"\u002F\u002F Fix: materialise once\n",[121,392,393],{"class":123,"line":161},[121,394,395],{},"var cached = users.ToList();\n",[121,397,398],{"class":123,"line":167},[121,399,400],{},"int count2  = cached.Count;   \u002F\u002F in-memory — no DB hit\n",[121,402,403],{"class":123,"line":172},[121,404,405],{},"var first2  = cached.First(); \u002F\u002F in-memory\n",[15,407,408],{},[25,409,410],{},"Source changes between iterations:",[112,412,414],{"className":114,"code":413,"language":116,"meta":117,"style":117},"var list = new List\u003Cint> { 1, 2, 3 };\nvar q = list.Where(n => n > 1);\nlist.Clear();           \u002F\u002F modify source\nforeach (var n in q)    \u002F\u002F yields nothing — source is empty\n    Console.WriteLine(n);\n",[40,415,416,421,426,431,436],{"__ignoreMap":117},[121,417,418],{"class":123,"line":124},[121,419,420],{},"var list = new List\u003Cint> { 1, 2, 3 };\n",[121,422,423],{"class":123,"line":130},[121,424,425],{},"var q = list.Where(n => n > 1);\n",[121,427,428],{"class":123,"line":137},[121,429,430],{},"list.Clear();           \u002F\u002F modify source\n",[121,432,433],{"class":123,"line":143},[121,434,435],{},"foreach (var n in q)    \u002F\u002F yields nothing — source is empty\n",[121,437,438],{"class":123,"line":149},[121,439,440],{},"    Console.WriteLine(n);\n",[15,442,443],{},[25,444,445],{},"Lazy evaluation in loops:",[112,447,449],{"className":114,"code":448,"language":116,"meta":117,"style":117},"var queries = new List\u003CIEnumerable\u003Cint>>();\nfor (int i = 0; i \u003C 3; i++)\n{\n    int captured = i;\n    queries.Add(Enumerable.Range(0, captured)); \u002F\u002F captured is correct because we copied\n}\n\u002F\u002F Without capturing: classic closure-over-loop-variable bug\n",[40,450,451,456,461,466,471,476,481],{"__ignoreMap":117},[121,452,453],{"class":123,"line":124},[121,454,455],{},"var queries = new List\u003CIEnumerable\u003Cint>>();\n",[121,457,458],{"class":123,"line":130},[121,459,460],{},"for (int i = 0; i \u003C 3; i++)\n",[121,462,463],{"class":123,"line":137},[121,464,465],{},"{\n",[121,467,468],{"class":123,"line":143},[121,469,470],{},"    int captured = i;\n",[121,472,473],{"class":123,"line":149},[121,474,475],{},"    queries.Add(Enumerable.Range(0, captured)); \u002F\u002F captured is correct because we copied\n",[121,477,478],{"class":123,"line":155},[121,479,480],{},"}\n",[121,482,483],{"class":123,"line":161},[121,484,485],{},"\u002F\u002F Without capturing: classic closure-over-loop-variable bug\n",[15,487,488,491,492,495,496,499],{},[25,489,490],{},"Rule:"," Call ",[40,493,494],{},".ToList()"," or ",[40,497,498],{},".ToArray()"," when you need a point-in-time snapshot,\nwill iterate more than once, or want to ensure a database query runs exactly once.",[10,501,503],{"id":502},"ienumerablet-vs-iqueryablet-the-most-critical-linq-distinction","IEnumerable\u003CT> vs IQueryable\u003CT> — the most critical LINQ distinction",[15,505,506],{},"This is the most common LINQ performance mistake in EF Core codebases.",[112,508,510],{"className":114,"code":509,"language":116,"meta":117,"style":117},"\u002F\u002F IEnumerable: loads ALL rows from DB, filters in memory\nIEnumerable\u003CUser> badApproach = db.Users; \u002F\u002F implicit ToList() does not happen yet\n                                            \u002F\u002F but AsEnumerable() forces in-memory\nvar activeUsers = badApproach.Where(u => u.IsActive).ToList();\n\u002F\u002F SQL: SELECT * FROM Users  ← ALL users loaded, then C# filters\n\n\u002F\u002F IQueryable: filter is translated to SQL\nIQueryable\u003CUser> goodApproach = db.Users;\nvar activeUsers2 = goodApproach.Where(u => u.IsActive).ToList();\n\u002F\u002F SQL: SELECT * FROM Users WHERE IsActive = 1  ← only matching rows fetched\n",[40,511,512,517,522,527,532,537,541,546,551,556],{"__ignoreMap":117},[121,513,514],{"class":123,"line":124},[121,515,516],{},"\u002F\u002F IEnumerable: loads ALL rows from DB, filters in memory\n",[121,518,519],{"class":123,"line":130},[121,520,521],{},"IEnumerable\u003CUser> badApproach = db.Users; \u002F\u002F implicit ToList() does not happen yet\n",[121,523,524],{"class":123,"line":137},[121,525,526],{},"                                            \u002F\u002F but AsEnumerable() forces in-memory\n",[121,528,529],{"class":123,"line":143},[121,530,531],{},"var activeUsers = badApproach.Where(u => u.IsActive).ToList();\n",[121,533,534],{"class":123,"line":149},[121,535,536],{},"\u002F\u002F SQL: SELECT * FROM Users  ← ALL users loaded, then C# filters\n",[121,538,539],{"class":123,"line":155},[121,540,134],{"emptyLinePlaceholder":133},[121,542,543],{"class":123,"line":161},[121,544,545],{},"\u002F\u002F IQueryable: filter is translated to SQL\n",[121,547,548],{"class":123,"line":167},[121,549,550],{},"IQueryable\u003CUser> goodApproach = db.Users;\n",[121,552,553],{"class":123,"line":172},[121,554,555],{},"var activeUsers2 = goodApproach.Where(u => u.IsActive).ToList();\n",[121,557,558],{"class":123,"line":178},[121,559,560],{},"\u002F\u002F SQL: SELECT * FROM Users WHERE IsActive = 1  ← only matching rows fetched\n",[15,562,563,564,566,567,570,571,573,574,577,578,581],{},"How this works: ",[40,565,75],{}," stores an ",[25,568,569],{},"expression tree"," — a data structure\nrepresenting the LINQ operations as objects (not compiled delegates). The LINQ provider\n(EF Core) walks the expression tree and generates SQL. ",[40,572,67],{}," stores\n",[25,575,576],{},"compiled delegates"," — once you are on ",[40,579,580],{},"IEnumerable",", the rest of the pipeline runs\nin C# memory regardless of where the data came from.",[112,583,585],{"className":114,"code":584,"language":116,"meta":117,"style":117},"\u002F\u002F AsEnumerable() switches from IQueryable to in-memory LINQ\n\u002F\u002F Use this when the provider cannot translate a particular operation:\nvar results = db.Users\n    .Where(u => u.IsActive)           \u002F\u002F translated to SQL: WHERE IsActive = 1\n    .AsEnumerable()                    \u002F\u002F switch to in-memory from here\n    .Where(u => MyComplexCSharpFn(u)) \u002F\u002F runs in C# — cannot be translated to SQL\n    .ToList();\n\u002F\u002F SQL: SELECT * FROM Users WHERE IsActive = 1\n\u002F\u002F Then: C# filters the result set with MyComplexCSharpFn\n",[40,586,587,592,597,602,607,612,617,622,627],{"__ignoreMap":117},[121,588,589],{"class":123,"line":124},[121,590,591],{},"\u002F\u002F AsEnumerable() switches from IQueryable to in-memory LINQ\n",[121,593,594],{"class":123,"line":130},[121,595,596],{},"\u002F\u002F Use this when the provider cannot translate a particular operation:\n",[121,598,599],{"class":123,"line":137},[121,600,601],{},"var results = db.Users\n",[121,603,604],{"class":123,"line":143},[121,605,606],{},"    .Where(u => u.IsActive)           \u002F\u002F translated to SQL: WHERE IsActive = 1\n",[121,608,609],{"class":123,"line":149},[121,610,611],{},"    .AsEnumerable()                    \u002F\u002F switch to in-memory from here\n",[121,613,614],{"class":123,"line":155},[121,615,616],{},"    .Where(u => MyComplexCSharpFn(u)) \u002F\u002F runs in C# — cannot be translated to SQL\n",[121,618,619],{"class":123,"line":161},[121,620,621],{},"    .ToList();\n",[121,623,624],{"class":123,"line":167},[121,625,626],{},"\u002F\u002F SQL: SELECT * FROM Users WHERE IsActive = 1\n",[121,628,629],{"class":123,"line":172},[121,630,631],{},"\u002F\u002F Then: C# filters the result set with MyComplexCSharpFn\n",[10,633,635],{"id":634},"the-most-important-linq-operators","The most important LINQ operators",[349,637,639],{"id":638},"select-and-selectmany","Select and SelectMany",[15,641,642,644,645,648],{},[40,643,60],{}," is 1-to-1 projection. ",[40,646,647],{},"SelectMany"," is 1-to-many then flatten.",[112,650,652],{"className":114,"code":651,"language":116,"meta":117,"style":117},"var sentences = new[] { \"hello world\", \"foo bar baz\" };\n\n\u002F\u002F Select — each string maps to a string array: IEnumerable\u003Cstring[]>\nvar words1 = sentences.Select(s => s.Split(' '));\n\u002F\u002F [ [\"hello\",\"world\"], [\"foo\",\"bar\",\"baz\"] ]\n\n\u002F\u002F SelectMany — flatten into IEnumerable\u003Cstring>\nvar words2 = sentences.SelectMany(s => s.Split(' '));\n\u002F\u002F [ \"hello\", \"world\", \"foo\", \"bar\", \"baz\" ]\n\n\u002F\u002F With index and result selector:\nvar indexed = sentences.SelectMany(\n    (sentence, i) => sentence.Split(' '),\n    (sentence, word) => $\"[{sentence[..3]}] {word}\"\n);\n",[40,653,654,659,663,668,673,678,682,687,692,697,701,706,711,716,721],{"__ignoreMap":117},[121,655,656],{"class":123,"line":124},[121,657,658],{},"var sentences = new[] { \"hello world\", \"foo bar baz\" };\n",[121,660,661],{"class":123,"line":130},[121,662,134],{"emptyLinePlaceholder":133},[121,664,665],{"class":123,"line":137},[121,666,667],{},"\u002F\u002F Select — each string maps to a string array: IEnumerable\u003Cstring[]>\n",[121,669,670],{"class":123,"line":143},[121,671,672],{},"var words1 = sentences.Select(s => s.Split(' '));\n",[121,674,675],{"class":123,"line":149},[121,676,677],{},"\u002F\u002F [ [\"hello\",\"world\"], [\"foo\",\"bar\",\"baz\"] ]\n",[121,679,680],{"class":123,"line":155},[121,681,134],{"emptyLinePlaceholder":133},[121,683,684],{"class":123,"line":161},[121,685,686],{},"\u002F\u002F SelectMany — flatten into IEnumerable\u003Cstring>\n",[121,688,689],{"class":123,"line":167},[121,690,691],{},"var words2 = sentences.SelectMany(s => s.Split(' '));\n",[121,693,694],{"class":123,"line":172},[121,695,696],{},"\u002F\u002F [ \"hello\", \"world\", \"foo\", \"bar\", \"baz\" ]\n",[121,698,699],{"class":123,"line":178},[121,700,134],{"emptyLinePlaceholder":133},[121,702,703],{"class":123,"line":184},[121,704,705],{},"\u002F\u002F With index and result selector:\n",[121,707,708],{"class":123,"line":190},[121,709,710],{},"var indexed = sentences.SelectMany(\n",[121,712,713],{"class":123,"line":196},[121,714,715],{},"    (sentence, i) => sentence.Split(' '),\n",[121,717,718],{"class":123,"line":202},[121,719,720],{},"    (sentence, word) => $\"[{sentence[..3]}] {word}\"\n",[121,722,724],{"class":123,"line":723},15,[121,725,726],{},");\n",[15,728,729,730,732,733,735],{},"Use ",[40,731,647],{}," when each element maps to a collection and you want a flat result.\nIt corresponds to nested ",[40,734,102],{}," loops.",[349,737,739],{"id":738},"first-firstordefault-single-singleordefault","First, FirstOrDefault, Single, SingleOrDefault",[112,741,743],{"className":114,"code":742,"language":116,"meta":117,"style":117},"var items = new[] { 3, 1, 4, 1, 5, 9 };\n\nitems.First();              \u002F\u002F 3 — throws if empty\nitems.FirstOrDefault();     \u002F\u002F 3 — returns default(int) = 0 if empty\nitems.First(x => x > 4);   \u002F\u002F 5 — first match; throws if no match\n\nitems.Single(x => x == 9); \u002F\u002F 9 — throws if 0 or 2+ matches\nitems.SingleOrDefault(x => x > 100); \u002F\u002F 0 — no match returns default; still throws if 2+ match\n",[40,744,745,750,754,759,764,769,773,778],{"__ignoreMap":117},[121,746,747],{"class":123,"line":124},[121,748,749],{},"var items = new[] { 3, 1, 4, 1, 5, 9 };\n",[121,751,752],{"class":123,"line":130},[121,753,134],{"emptyLinePlaceholder":133},[121,755,756],{"class":123,"line":137},[121,757,758],{},"items.First();              \u002F\u002F 3 — throws if empty\n",[121,760,761],{"class":123,"line":143},[121,762,763],{},"items.FirstOrDefault();     \u002F\u002F 3 — returns default(int) = 0 if empty\n",[121,765,766],{"class":123,"line":149},[121,767,768],{},"items.First(x => x > 4);   \u002F\u002F 5 — first match; throws if no match\n",[121,770,771],{"class":123,"line":155},[121,772,134],{"emptyLinePlaceholder":133},[121,774,775],{"class":123,"line":161},[121,776,777],{},"items.Single(x => x == 9); \u002F\u002F 9 — throws if 0 or 2+ matches\n",[121,779,780],{"class":123,"line":167},[121,781,782],{},"items.SingleOrDefault(x => x > 100); \u002F\u002F 0 — no match returns default; still throws if 2+ match\n",[15,784,729,785,788,789,792],{},[40,786,787],{},"Single","\u002F",[40,790,791],{},"SingleOrDefault"," when exactly one result is a business invariant (like\nlooking up by primary key). The exception it throws when multiple matches exist is a\nuseful contract assertion.",[349,794,63],{"id":795},"groupby",[15,797,798,800,801,804,805,80],{},[40,799,63],{}," partitions a sequence. Each group has a ",[40,802,803],{},"Key"," and is an ",[40,806,807],{},"IEnumerable\u003CTElement>",[112,809,811],{"className":114,"code":810,"language":116,"meta":117,"style":117},"var words = new[] { \"ant\", \"bear\", \"cat\", \"ape\", \"bat\", \"crow\" };\n\nvar byFirstLetter = words.GroupBy(w => w[0]);\nforeach (var g in byFirstLetter)\n    Console.WriteLine($\"{g.Key}: {string.Join(\", \", g)}\");\n\u002F\u002F a: ant, ape\n\u002F\u002F b: bear, bat\n\u002F\u002F c: cat, crow\n\n\u002F\u002F Group + aggregate (the common pattern):\nvar wordCountByLetter = words\n    .GroupBy(w => w[0])\n    .Select(g => new { Letter = g.Key, Count = g.Count() });\n",[40,812,813,818,822,827,832,837,842,847,852,856,861,866,871],{"__ignoreMap":117},[121,814,815],{"class":123,"line":124},[121,816,817],{},"var words = new[] { \"ant\", \"bear\", \"cat\", \"ape\", \"bat\", \"crow\" };\n",[121,819,820],{"class":123,"line":130},[121,821,134],{"emptyLinePlaceholder":133},[121,823,824],{"class":123,"line":137},[121,825,826],{},"var byFirstLetter = words.GroupBy(w => w[0]);\n",[121,828,829],{"class":123,"line":143},[121,830,831],{},"foreach (var g in byFirstLetter)\n",[121,833,834],{"class":123,"line":149},[121,835,836],{},"    Console.WriteLine($\"{g.Key}: {string.Join(\", \", g)}\");\n",[121,838,839],{"class":123,"line":155},[121,840,841],{},"\u002F\u002F a: ant, ape\n",[121,843,844],{"class":123,"line":161},[121,845,846],{},"\u002F\u002F b: bear, bat\n",[121,848,849],{"class":123,"line":167},[121,850,851],{},"\u002F\u002F c: cat, crow\n",[121,853,854],{"class":123,"line":172},[121,855,134],{"emptyLinePlaceholder":133},[121,857,858],{"class":123,"line":178},[121,859,860],{},"\u002F\u002F Group + aggregate (the common pattern):\n",[121,862,863],{"class":123,"line":184},[121,864,865],{},"var wordCountByLetter = words\n",[121,867,868],{"class":123,"line":190},[121,869,870],{},"    .GroupBy(w => w[0])\n",[121,872,873],{"class":123,"line":196},[121,874,875],{},"    .Select(g => new { Letter = g.Key, Count = g.Count() });\n",[15,877,878,879,881,882,884,885,888,889,891,892,895,896,898],{},"In EF Core, ",[40,880,63],{}," on ",[40,883,75],{}," translates to ",[40,886,887],{},"GROUP BY",". However, complex\n",[40,890,63],{}," projections may not translate — if EF Core throws at runtime, add\n",[40,893,894],{},".AsEnumerable()"," before ",[40,897,63],{}," to force in-memory grouping.",[349,900,902],{"id":901},"aggregate-foldreduce","Aggregate (fold\u002Freduce)",[112,904,906],{"className":114,"code":905,"language":116,"meta":117,"style":117},"var nums = new[] { 1, 2, 3, 4, 5 };\n\n\u002F\u002F Without seed — uses first element as initial accumulator:\nint sum  = nums.Aggregate((acc, n) => acc + n); \u002F\u002F 15\nint prod = nums.Aggregate((acc, n) => acc * n); \u002F\u002F 120\n\n\u002F\u002F With seed:\nint sumPlus100 = nums.Aggregate(100, (acc, n) => acc + n); \u002F\u002F 115\n\n\u002F\u002F With result selector (seed, fold, transform):\nstring result = nums.Aggregate(\n    new List\u003Cstring>(),\n    (list, n) => { list.Add(n.ToString()); return list; },\n    list => string.Join(\"-\", list)\n); \u002F\u002F \"1-2-3-4-5\"\n",[40,907,908,913,917,922,927,932,936,941,946,950,955,960,965,970,975],{"__ignoreMap":117},[121,909,910],{"class":123,"line":124},[121,911,912],{},"var nums = new[] { 1, 2, 3, 4, 5 };\n",[121,914,915],{"class":123,"line":130},[121,916,134],{"emptyLinePlaceholder":133},[121,918,919],{"class":123,"line":137},[121,920,921],{},"\u002F\u002F Without seed — uses first element as initial accumulator:\n",[121,923,924],{"class":123,"line":143},[121,925,926],{},"int sum  = nums.Aggregate((acc, n) => acc + n); \u002F\u002F 15\n",[121,928,929],{"class":123,"line":149},[121,930,931],{},"int prod = nums.Aggregate((acc, n) => acc * n); \u002F\u002F 120\n",[121,933,934],{"class":123,"line":155},[121,935,134],{"emptyLinePlaceholder":133},[121,937,938],{"class":123,"line":161},[121,939,940],{},"\u002F\u002F With seed:\n",[121,942,943],{"class":123,"line":167},[121,944,945],{},"int sumPlus100 = nums.Aggregate(100, (acc, n) => acc + n); \u002F\u002F 115\n",[121,947,948],{"class":123,"line":172},[121,949,134],{"emptyLinePlaceholder":133},[121,951,952],{"class":123,"line":178},[121,953,954],{},"\u002F\u002F With result selector (seed, fold, transform):\n",[121,956,957],{"class":123,"line":184},[121,958,959],{},"string result = nums.Aggregate(\n",[121,961,962],{"class":123,"line":190},[121,963,964],{},"    new List\u003Cstring>(),\n",[121,966,967],{"class":123,"line":196},[121,968,969],{},"    (list, n) => { list.Add(n.ToString()); return list; },\n",[121,971,972],{"class":123,"line":202},[121,973,974],{},"    list => string.Join(\"-\", list)\n",[121,976,977],{"class":123,"line":723},[121,978,979],{},"); \u002F\u002F \"1-2-3-4-5\"\n",[349,981,983],{"id":982},"zip","Zip",[112,985,987],{"className":114,"code":986,"language":116,"meta":117,"style":117},"var names  = new[] { \"Alice\", \"Bob\", \"Carol\" };\nvar scores = new[] { 92, 85, 78 };\n\n\u002F\u002F Pairs positional elements:\nvar paired = names.Zip(scores, (name, score) => $\"{name}: {score}\");\n\u002F\u002F [ \"Alice: 92\", \"Bob: 85\", \"Carol: 78\" ]\n\n\u002F\u002F C# 6+ — no selector: returns tuples\nforeach (var (name, score) in names.Zip(scores))\n    Console.WriteLine($\"{name} scored {score}\");\n",[40,988,989,994,999,1003,1008,1013,1018,1022,1027,1032],{"__ignoreMap":117},[121,990,991],{"class":123,"line":124},[121,992,993],{},"var names  = new[] { \"Alice\", \"Bob\", \"Carol\" };\n",[121,995,996],{"class":123,"line":130},[121,997,998],{},"var scores = new[] { 92, 85, 78 };\n",[121,1000,1001],{"class":123,"line":137},[121,1002,134],{"emptyLinePlaceholder":133},[121,1004,1005],{"class":123,"line":143},[121,1006,1007],{},"\u002F\u002F Pairs positional elements:\n",[121,1009,1010],{"class":123,"line":149},[121,1011,1012],{},"var paired = names.Zip(scores, (name, score) => $\"{name}: {score}\");\n",[121,1014,1015],{"class":123,"line":155},[121,1016,1017],{},"\u002F\u002F [ \"Alice: 92\", \"Bob: 85\", \"Carol: 78\" ]\n",[121,1019,1020],{"class":123,"line":161},[121,1021,134],{"emptyLinePlaceholder":133},[121,1023,1024],{"class":123,"line":167},[121,1025,1026],{},"\u002F\u002F C# 6+ — no selector: returns tuples\n",[121,1028,1029],{"class":123,"line":172},[121,1030,1031],{},"foreach (var (name, score) in names.Zip(scores))\n",[121,1033,1034],{"class":123,"line":178},[121,1035,1036],{},"    Console.WriteLine($\"{name} scored {score}\");\n",[10,1038,1040],{"id":1039},"common-linq-pitfalls","Common LINQ pitfalls",[349,1042,1044],{"id":1043},"n1-queries-in-ef-core","N+1 queries in EF Core",[112,1046,1048],{"className":114,"code":1047,"language":116,"meta":117,"style":117},"\u002F\u002F N+1: one query for orders, one per order for customer name\nvar orders = db.Orders.ToList();\nforeach (var o in orders)\n    Console.WriteLine(db.Customers.Find(o.CustomerId)?.Name); \u002F\u002F 1 query per order!\n\n\u002F\u002F Eager load with Include:\nvar orders2 = db.Orders.Include(o => o.Customer).ToList();\n\u002F\u002F One JOIN query fetches everything\n",[40,1049,1050,1055,1060,1065,1070,1074,1079,1084],{"__ignoreMap":117},[121,1051,1052],{"class":123,"line":124},[121,1053,1054],{},"\u002F\u002F N+1: one query for orders, one per order for customer name\n",[121,1056,1057],{"class":123,"line":130},[121,1058,1059],{},"var orders = db.Orders.ToList();\n",[121,1061,1062],{"class":123,"line":137},[121,1063,1064],{},"foreach (var o in orders)\n",[121,1066,1067],{"class":123,"line":143},[121,1068,1069],{},"    Console.WriteLine(db.Customers.Find(o.CustomerId)?.Name); \u002F\u002F 1 query per order!\n",[121,1071,1072],{"class":123,"line":149},[121,1073,134],{"emptyLinePlaceholder":133},[121,1075,1076],{"class":123,"line":155},[121,1077,1078],{},"\u002F\u002F Eager load with Include:\n",[121,1080,1081],{"class":123,"line":161},[121,1082,1083],{},"var orders2 = db.Orders.Include(o => o.Customer).ToList();\n",[121,1085,1086],{"class":123,"line":167},[121,1087,1088],{},"\u002F\u002F One JOIN query fetches everything\n",[349,1090,1092,1093,1096,1097],{"id":1091},"calling-count-instead-of-any","Calling ",[40,1094,1095],{},".Count()"," instead of ",[40,1098,1099],{},".Any()",[112,1101,1103],{"className":114,"code":1102,"language":116,"meta":117,"style":117},"\u002F\u002F Iterates entire collection to count:\nif (list.Count() > 0) { }\n\n\u002F\u002F Stops at first element:\nif (list.Any()) { }\n",[40,1104,1105,1110,1115,1119,1124],{"__ignoreMap":117},[121,1106,1107],{"class":123,"line":124},[121,1108,1109],{},"\u002F\u002F Iterates entire collection to count:\n",[121,1111,1112],{"class":123,"line":130},[121,1113,1114],{},"if (list.Count() > 0) { }\n",[121,1116,1117],{"class":123,"line":137},[121,1118,134],{"emptyLinePlaceholder":133},[121,1120,1121],{"class":123,"line":143},[121,1122,1123],{},"\u002F\u002F Stops at first element:\n",[121,1125,1126],{"class":123,"line":149},[121,1127,1128],{},"if (list.Any()) { }\n",[349,1130,1132],{"id":1131},"multiple-enumeration-of-a-deferred-source","Multiple enumeration of a deferred source",[112,1134,1136],{"className":114,"code":1135,"language":116,"meta":117,"style":117},"\u002F\u002F Executes the query twice (two DB round trips):\nvoid Process(IEnumerable\u003CUser> users)\n{\n    Console.WriteLine(users.Count()); \u002F\u002F query 1\n    foreach (var u in users) { }     \u002F\u002F query 2\n}\n\n\u002F\u002F Materialise once at the call site:\nProcess(db.Users.Where(u => u.IsActive).ToList());\n",[40,1137,1138,1143,1148,1152,1157,1162,1166,1170,1175],{"__ignoreMap":117},[121,1139,1140],{"class":123,"line":124},[121,1141,1142],{},"\u002F\u002F Executes the query twice (two DB round trips):\n",[121,1144,1145],{"class":123,"line":130},[121,1146,1147],{},"void Process(IEnumerable\u003CUser> users)\n",[121,1149,1150],{"class":123,"line":137},[121,1151,465],{},[121,1153,1154],{"class":123,"line":143},[121,1155,1156],{},"    Console.WriteLine(users.Count()); \u002F\u002F query 1\n",[121,1158,1159],{"class":123,"line":149},[121,1160,1161],{},"    foreach (var u in users) { }     \u002F\u002F query 2\n",[121,1163,1164],{"class":123,"line":155},[121,1165,480],{},[121,1167,1168],{"class":123,"line":161},[121,1169,134],{"emptyLinePlaceholder":133},[121,1171,1172],{"class":123,"line":167},[121,1173,1174],{},"\u002F\u002F Materialise once at the call site:\n",[121,1176,1177],{"class":123,"line":172},[121,1178,1179],{},"Process(db.Users.Where(u => u.IsActive).ToList());\n",[10,1181,1183],{"id":1182},"recap","Recap",[15,1185,1186,1187,1190,1191,1193,1194,1196,1197,1200,1201,495,1203,1205,1206,1208,1209,1212,1213,1215,1216,1218,1219,788,1221,1223,1224,1226,1227,1230,1231,1234,1235,1237],{},"LINQ is a ",[25,1188,1189],{},"declarative query model"," built into C# through extension methods on\n",[40,1192,67],{}," and ",[40,1195,75],{},". Its most important characteristic is ",[25,1198,1199],{},"deferred\nexecution"," — queries describe computation but don't run until iterated; materialise\nwith ",[40,1202,494],{},[40,1204,498],{}," when you need a snapshot or will iterate more than\nonce. ",[40,1207,67],{}," runs LINQ operators ",[25,1210,1211],{},"in memory"," (LINQ to Objects); ",[40,1214,75],{},"\ntranslates operators to the data source's query language (SQL via EF Core). Always\nkeep database-facing LINQ on ",[40,1217,75],{}," to avoid loading entire tables. The three\noperators to understand deeply are ",[40,1220,60],{},[40,1222,647],{}," (projection and flattening),\n",[40,1225,63],{}," (partitioning), and ",[40,1228,1229],{},"Aggregate"," (the general fold). The three mistakes to\navoid are N+1 queries, multiple enumeration of deferred sources, and switching from\n",[40,1232,1233],{},"IQueryable"," to ",[40,1236,580],{}," too early in the pipeline.",[1239,1240,1241],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":117,"searchDepth":130,"depth":130,"links":1243},[1244,1245,1246,1247,1250,1251,1258,1264],{"id":12,"depth":130,"text":13},{"id":20,"depth":130,"text":21},{"id":106,"depth":130,"text":107},{"id":228,"depth":130,"text":229,"children":1248},[1249],{"id":351,"depth":137,"text":352},{"id":502,"depth":130,"text":503},{"id":634,"depth":130,"text":635,"children":1252},[1253,1254,1255,1256,1257],{"id":638,"depth":137,"text":639},{"id":738,"depth":137,"text":739},{"id":795,"depth":137,"text":63},{"id":901,"depth":137,"text":902},{"id":982,"depth":137,"text":983},{"id":1039,"depth":130,"text":1040,"children":1259},[1260,1261,1263],{"id":1043,"depth":137,"text":1044},{"id":1091,"depth":137,"text":1262},"Calling .Count() instead of .Any()",{"id":1131,"depth":137,"text":1132},{"id":1182,"depth":130,"text":1183},"How LINQ defers execution and why it matters — the difference between IEnumerable and IQueryable, common operators that trip up developers, and the performance pitfalls to watch for in database queries.","medium","md",".NET Core","dotnet",{},"\u002Fblog\u002Fdotnet-linq-deferred-execution-iqueryable","\u002Fdotnet\u002Ffundamentals\u002Flinq",{"title":5,"description":1265},"blog\u002Fdotnet-linq-deferred-execution-iqueryable","LINQ","Fundamentals","fundamentals","2026-06-22","x1U-B467OsD9guuidjyGIwvNKHLIaINlbAFMF5vVzlU",1782244087793]