|
1 | 1 | using Microsoft.EntityFrameworkCore; |
2 | 2 | using ReadmeSample; |
3 | 3 | using ReadmeSample.Dtos; |
4 | | -using ReadmeSample.Entities; |
5 | 4 | using ReadmeSample.Extensions; |
6 | 5 | using Spectre.Console; |
7 | 6 | using static ReadmeSample.ConsoleHelper; |
|
22 | 21 | // Bootstrap |
23 | 22 | // ───────────────────────────────────────────────────────────────────────────── |
24 | 23 | await using var dbContext = new ApplicationDbContext(); |
25 | | -dbContext.Database.EnsureDeleted(); |
26 | | -dbContext.Database.EnsureCreated(); |
27 | | - |
28 | | -// ───────────────────────────────────────────────────────────────────────────── |
29 | | -// Seed data |
30 | | -// ───────────────────────────────────────────────────────────────────────────── |
31 | | -var user = new User { UserName = "Jon", EmailAddress = "jon@doe.com" }; |
32 | | -var supplier = new Supplier { Name = "Acme Stationery" }; |
33 | | -var pen = new Product { Name = "Blue Pen", ListPrice = 1.50m, Supplier = supplier }; |
34 | | -var book = new Product { Name = "C# in Depth", ListPrice = 35.99m }; // no supplier → null-conditional demo |
35 | | - |
36 | | -var fulfilledOrder = new Order |
37 | | -{ |
38 | | - User = user, TaxRate = .19m, Status = OrderStatus.Fulfilled, |
39 | | - CreatedDate = DateTime.UtcNow.AddDays(-2), FulfilledDate = DateTime.UtcNow.AddDays(-1), |
40 | | - Items = [new OrderItem { Product = pen, Quantity = 5 }, new OrderItem { Product = book, Quantity = 1 }], |
41 | | -}; |
42 | | -var pendingOrder = new Order |
43 | | -{ |
44 | | - User = user, TaxRate = .19m, Status = OrderStatus.Pending, |
45 | | - CreatedDate = DateTime.UtcNow, FulfilledDate = null, |
46 | | - Items = [new OrderItem { Product = pen, Quantity = 2 }], |
47 | | -}; |
48 | | - |
49 | | -dbContext.AddRange(user, supplier, pen, book, fulfilledOrder, pendingOrder); |
50 | | -dbContext.SaveChanges(); |
51 | 24 |
|
52 | 25 | // ───────────────────────────────────────────────────────────────────────────── |
53 | 26 | // Feature 1 — Properties & methods |
|
61 | 34 | }); |
62 | 35 |
|
63 | 36 | ShowSql(totalsQuery.ToQueryString()); |
64 | | -foreach (var row in totalsQuery) |
65 | | -{ |
66 | | - AnsiConsole.MarkupLine( |
67 | | - $" [dim]Order #{row.Id}[/]" |
68 | | - + $" subtotal={Money(row.Subtotal)}" |
69 | | - + $" tax={Money(row.Tax)}" |
70 | | - + $" grand total={Money(row.GrandTotal)}" |
71 | | - + $" [dim]−10%[/]={Money(row.Discounted10Pct)}"); |
72 | | -} |
73 | 37 |
|
74 | 38 | // ───────────────────────────────────────────────────────────────────────────── |
75 | 39 | // Feature 2 — Extension methods |
|
81 | 45 | .Select(u => new { u.UserName, LatestOrderGrandTotal = u.GetMostRecentOrder()!.GrandTotal }); |
82 | 46 |
|
83 | 47 | ShowSql(recentQuery.ToQueryString()); |
84 | | -var recent = recentQuery.First(); |
85 | | -AnsiConsole.MarkupLine( |
86 | | - $" [white]{Markup.Escape(recent.UserName)}[/]'s most recent order: {Money(recent.LatestOrderGrandTotal)}"); |
87 | 48 |
|
88 | 49 | // ───────────────────────────────────────────────────────────────────────────── |
89 | 50 | // Feature 3 — Constructor projections |
|
93 | 54 | var dtoQuery = dbContext.Orders.Select(o => new OrderSummaryDto(o)); |
94 | 55 |
|
95 | 56 | ShowSql(dtoQuery.ToQueryString()); |
96 | | -foreach (var dto in dtoQuery) |
97 | | -{ |
98 | | - AnsiConsole.MarkupLine( |
99 | | - $" [dim]#{dto.Id}[/] [white]{Markup.Escape(dto.UserName ?? "")}[/]" |
100 | | - + $" — {Money(dto.GrandTotal)}" |
101 | | - + $" status={StatusMark(dto.StatusName)}" |
102 | | - + $" priority={PriorityMark(dto.PriorityLabel)}"); |
103 | | -} |
104 | 57 |
|
105 | 58 | // ───────────────────────────────────────────────────────────────────────────── |
106 | 59 | // Feature 4 — Method overloads |
|
112 | 65 | .Select(u => new { u.UserName, LatestAnyOrderTotal = u.GetMostRecentOrderForUser(true)!.GrandTotal }); |
113 | 66 |
|
114 | 67 | ShowSql(withPendingQuery.ToQueryString()); |
115 | | -var withPending = withPendingQuery.First(); |
116 | | -AnsiConsole.MarkupLine( |
117 | | - $" [white]{Markup.Escape(withPending.UserName)}[/]'s most recent order (incl. pending): {Money(withPending.LatestAnyOrderTotal)}"); |
118 | 68 |
|
119 | 69 | // ───────────────────────────────────────────────────────────────────────────── |
120 | 70 | // Feature 5 — Pattern matching |
|
124 | 74 | var priorityQuery = dbContext.Orders.Select(o => new { o.Id, o.GrandTotal, o.PriorityLabel }); |
125 | 75 |
|
126 | 76 | ShowSql(priorityQuery.ToQueryString()); |
127 | | -foreach (var row in priorityQuery) |
128 | | -{ |
129 | | - AnsiConsole.MarkupLine( |
130 | | - $" [dim]Order #{row.Id}[/] {Money(row.GrandTotal)} → priority={PriorityMark(row.PriorityLabel)}"); |
131 | | -} |
132 | 77 |
|
133 | 78 | // ───────────────────────────────────────────────────────────────────────────── |
134 | 79 | // Feature 6 — Block-bodied members |
|
138 | 83 | var shippingQuery = dbContext.Orders.Select(o => new { o.Id, ShippingCategory = o.GetShippingCategory() }); |
139 | 84 |
|
140 | 85 | ShowSql(shippingQuery.ToQueryString()); |
141 | | -foreach (var row in shippingQuery) |
142 | | -{ |
143 | | - AnsiConsole.MarkupLine( |
144 | | - $" [dim]Order #{row.Id}[/] shipping=[bold]{Markup.Escape(row.ShippingCategory)}[/]"); |
145 | | -} |
146 | 86 |
|
147 | 87 | // ───────────────────────────────────────────────────────────────────────────── |
148 | 88 | // Feature 7 — Null-conditional rewriting |
|
152 | 92 | var supplierQuery = dbContext.Products.Select(p => new { p.Name, p.SupplierName }); |
153 | 93 |
|
154 | 94 | ShowSql(supplierQuery.ToQueryString()); |
155 | | -foreach (var row in supplierQuery) |
156 | | -{ |
157 | | - var sup = row.SupplierName is null |
158 | | - ? "[dim](none)[/]" |
159 | | - : $"[bold green]{Markup.Escape(row.SupplierName)}[/]"; |
160 | | - AnsiConsole.MarkupLine($" [white]{Markup.Escape(row.Name)}[/] supplier={sup}"); |
161 | | -} |
162 | 95 |
|
163 | 96 | // ───────────────────────────────────────────────────────────────────────────── |
164 | 97 | // Feature 8 — Enum method expansion |
|
168 | 101 | var statusQuery = dbContext.Orders.Select(o => new { o.Id, o.Status, o.StatusDisplayName }); |
169 | 102 |
|
170 | 103 | ShowSql(statusQuery.ToQueryString()); |
171 | | -foreach (var row in statusQuery) |
172 | | -{ |
173 | | - AnsiConsole.MarkupLine( |
174 | | - $" [dim]Order #{row.Id}[/] [dim]{row.Status}[/] → {StatusMark(row.StatusDisplayName)}"); |
175 | | -} |
176 | 104 |
|
177 | 105 | // ───────────────────────────────────────────────────────────────────────────── |
178 | 106 | // Feature 9 — UseMemberBody |
|
182 | 110 | var highValueQuery = dbContext.Orders.Select(o => new { o.Id, o.GrandTotal, o.IsHighValueOrder }); |
183 | 111 |
|
184 | 112 | ShowSql(highValueQuery.ToQueryString()); |
185 | | -foreach (var row in highValueQuery) |
186 | | -{ |
187 | | - AnsiConsole.MarkupLine( |
188 | | - $" [dim]Order #{row.Id}[/] {Money(row.GrandTotal)} → high-value={BoolMark(row.IsHighValueOrder)}"); |
189 | | -} |
190 | 113 |
|
191 | 114 | // ───────────────────────────────────────────────────────────────────────────── |
192 | 115 | // Feature 10 — Compatibility mode |
|
0 commit comments