@zimezone/z-command 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -1
- package/templates/agents/api-documenter.agent.md +161 -0
- package/templates/agents/architect-review.agent.md +146 -0
- package/templates/agents/arm-cortex-expert.agent.md +288 -0
- package/templates/agents/backend-architect.agent.md +309 -0
- package/templates/agents/backend-security-coder.agent.md +152 -0
- package/templates/agents/bash-pro.agent.md +285 -0
- package/templates/agents/c-pro.agent.md +35 -0
- package/templates/agents/c4-code.agent.md +320 -0
- package/templates/agents/c4-component.agent.md +227 -0
- package/templates/agents/c4-container.agent.md +248 -0
- package/templates/agents/c4-context.agent.md +235 -0
- package/templates/agents/conductor-validator.agent.md +245 -0
- package/templates/agents/csharp-pro.agent.md +38 -0
- package/templates/agents/customer-support.agent.md +148 -0
- package/templates/agents/database-admin.agent.md +142 -0
- package/templates/agents/database-architect.agent.md +238 -0
- package/templates/agents/database-optimizer.agent.md +144 -0
- package/templates/agents/debugger.agent.md +30 -0
- package/templates/agents/deployment-engineer.agent.md +0 -0
- package/templates/agents/devops-troubleshooter.agent.md +138 -0
- package/templates/agents/django-pro.agent.md +159 -0
- package/templates/agents/docs-architect.agent.md +77 -0
- package/templates/agents/dotnet-architect.agent.md +175 -0
- package/templates/agents/dx-optimizer.agent.md +63 -0
- package/templates/agents/elixir-pro.agent.md +38 -0
- package/templates/agents/error-detective.agent.md +32 -0
- package/templates/agents/event-sourcing-architect.agent.md +42 -0
- package/templates/agents/fastapi-pro.agent.md +171 -0
- package/templates/agents/firmware-analyst.agent.md +330 -0
- package/templates/agents/frontend-security-coder.agent.md +149 -0
- package/templates/agents/haskell-pro.agent.md +37 -0
- package/templates/agents/hr-pro.agent.md +105 -0
- package/templates/agents/incident-responder.agent.md +190 -0
- package/templates/agents/ios-developer.agent.md +198 -0
- package/templates/agents/java-pro.agent.md +156 -0
- package/templates/agents/javascript-pro.agent.md +35 -0
- package/templates/agents/julia-pro.agent.md +187 -0
- package/templates/agents/legal-advisor.agent.md +49 -0
- package/templates/agents/malware-analyst.agent.md +272 -0
- package/templates/agents/mermaid-expert.agent.md +39 -0
- package/templates/agents/minecraft-bukkit-pro.agent.md +104 -0
- package/templates/agents/mobile-security-coder.agent.md +163 -0
- package/templates/agents/monorepo-architect.agent.md +44 -0
- package/templates/agents/observability-engineer.agent.md +228 -0
- package/templates/agents/performance-engineer.agent.md +167 -0
- package/templates/agents/php-pro.agent.md +43 -0
- package/templates/agents/posix-shell-pro.agent.md +284 -0
- package/templates/agents/quant-analyst.agent.md +32 -0
- package/templates/agents/reference-builder.agent.md +167 -0
- package/templates/agents/reverse-engineer.agent.md +202 -0
- package/templates/agents/risk-manager.agent.md +41 -0
- package/templates/agents/ruby-pro.agent.md +35 -0
- package/templates/agents/rust-pro.agent.md +156 -0
- package/templates/agents/sales-automator.agent.md +35 -0
- package/templates/agents/scala-pro.agent.md +60 -0
- package/templates/agents/search-specialist.agent.md +59 -0
- package/templates/agents/security-auditor.agent.md +138 -0
- package/templates/agents/seo-authority-builder.agent.md +116 -0
- package/templates/agents/seo-cannibalization-detector.agent.md +103 -0
- package/templates/agents/seo-content-auditor.agent.md +63 -0
- package/templates/agents/seo-content-planner.agent.md +88 -0
- package/templates/agents/seo-content-refresher.agent.md +98 -0
- package/templates/agents/seo-content-writer.agent.md +76 -0
- package/templates/agents/seo-keyword-strategist.agent.md +75 -0
- package/templates/agents/seo-meta-optimizer.agent.md +72 -0
- package/templates/agents/seo-snippet-hunter.agent.md +94 -0
- package/templates/agents/seo-structure-architect.agent.md +88 -0
- package/templates/agents/service-mesh-expert.agent.md +41 -0
- package/templates/agents/sql-pro.agent.md +146 -0
- package/templates/agents/tdd-orchestrator.agent.md +183 -0
- package/templates/agents/temporal-python-pro.agent.md +349 -0
- package/templates/agents/terraform-specialist.agent.md +137 -0
- package/templates/agents/test-automator.agent.md +203 -0
- package/templates/agents/threat-modeling-expert.agent.md +44 -0
- package/templates/agents/tutorial-engineer.agent.md +118 -0
- package/templates/agents/ui-ux-designer.agent.md +188 -0
- package/templates/agents/ui-visual-validator.agent.md +192 -0
- package/templates/agents/vector-database-engineer.agent.md +43 -0
- package/templates/skills/angular-migration/SKILL.md +410 -0
- package/templates/skills/api-design-principles/SKILL.md +528 -0
- package/templates/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/templates/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/templates/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/templates/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/templates/skills/architecture-decision-records/SKILL.md +428 -0
- package/templates/skills/architecture-patterns/SKILL.md +494 -0
- package/templates/skills/async-python-patterns/SKILL.md +694 -0
- package/templates/skills/auth-implementation-patterns/SKILL.md +634 -0
- package/templates/skills/changelog-automation/SKILL.md +552 -0
- package/templates/skills/code-review-excellence/SKILL.md +520 -0
- package/templates/skills/competitive-landscape/SKILL.md +479 -0
- package/templates/skills/context-driven-development/SKILL.md +385 -0
- package/templates/skills/cost-optimization/SKILL.md +274 -0
- package/templates/skills/cqrs-implementation/SKILL.md +554 -0
- package/templates/skills/data-quality-frameworks/SKILL.md +587 -0
- package/templates/skills/data-storytelling/SKILL.md +453 -0
- package/templates/skills/database-migration/SKILL.md +424 -0
- package/templates/skills/dbt-transformation-patterns/SKILL.md +561 -0
- package/templates/skills/debugging-strategies/SKILL.md +527 -0
- package/templates/skills/defi-protocol-templates/SKILL.md +454 -0
- package/templates/skills/dependency-upgrade/SKILL.md +409 -0
- package/templates/skills/deployment-pipeline-design/SKILL.md +359 -0
- package/templates/skills/distributed-tracing/SKILL.md +438 -0
- package/templates/skills/dotnet-backend-patterns/SKILL.md +815 -0
- package/templates/skills/dotnet-backend-patterns/assets/repository-template.cs +523 -0
- package/templates/skills/dotnet-backend-patterns/assets/service-template.cs +336 -0
- package/templates/skills/dotnet-backend-patterns/references/dapper-patterns.md +544 -0
- package/templates/skills/dotnet-backend-patterns/references/ef-core-best-practices.md +355 -0
- package/templates/skills/e2e-testing-patterns/SKILL.md +547 -0
- package/templates/skills/employment-contract-templates/SKILL.md +507 -0
- package/templates/skills/error-handling-patterns/SKILL.md +636 -0
- package/templates/skills/event-store-design/SKILL.md +437 -0
- package/templates/skills/fastapi-templates/SKILL.md +567 -0
- package/templates/skills/git-advanced-workflows/SKILL.md +400 -0
- package/templates/skills/github-actions-templates/SKILL.md +333 -0
- package/templates/skills/go-concurrency-patterns/SKILL.md +655 -0
- package/templates/skills/grafana-dashboards/SKILL.md +369 -0
- package/templates/skills/helm-chart-scaffolding/SKILL.md +544 -0
- package/templates/skills/helm-chart-scaffolding/assets/Chart.yaml.template +42 -0
- package/templates/skills/helm-chart-scaffolding/assets/values.yaml.template +185 -0
- package/templates/skills/helm-chart-scaffolding/references/chart-structure.md +500 -0
- package/templates/skills/helm-chart-scaffolding/scripts/validate-chart.sh +244 -0
- package/templates/skills/javascript-testing-patterns/SKILL.md +1025 -0
- package/templates/skills/langchain-architecture/SKILL.md +338 -0
- package/templates/skills/llm-evaluation/SKILL.md +471 -0
- package/templates/skills/microservices-patterns/SKILL.md +595 -0
- package/templates/skills/modern-javascript-patterns/SKILL.md +911 -0
- package/templates/skills/monorepo-management/SKILL.md +622 -0
- package/templates/skills/nextjs-app-router-patterns/SKILL.md +544 -0
- package/templates/skills/nodejs-backend-patterns/SKILL.md +1020 -0
- package/templates/skills/nx-workspace-patterns/SKILL.md +452 -0
- package/templates/skills/openapi-spec-generation/SKILL.md +1028 -0
- package/templates/skills/paypal-integration/SKILL.md +467 -0
- package/templates/skills/pci-compliance/SKILL.md +466 -0
- package/templates/skills/postgresql/SKILL.md +204 -0
- package/templates/skills/projection-patterns/SKILL.md +490 -0
- package/templates/skills/prometheus-configuration/SKILL.md +392 -0
- package/templates/skills/prompt-engineering-patterns/SKILL.md +201 -0
- package/templates/skills/prompt-engineering-patterns/assets/few-shot-examples.json +106 -0
- package/templates/skills/prompt-engineering-patterns/assets/prompt-template-library.md +246 -0
- package/templates/skills/prompt-engineering-patterns/references/chain-of-thought.md +399 -0
- package/templates/skills/prompt-engineering-patterns/references/few-shot-learning.md +369 -0
- package/templates/skills/prompt-engineering-patterns/references/prompt-optimization.md +414 -0
- package/templates/skills/prompt-engineering-patterns/references/prompt-templates.md +470 -0
- package/templates/skills/prompt-engineering-patterns/references/system-prompts.md +189 -0
- package/templates/skills/prompt-engineering-patterns/scripts/optimize-prompt.py +279 -0
- package/templates/skills/python-packaging/SKILL.md +870 -0
- package/templates/skills/python-performance-optimization/SKILL.md +869 -0
- package/templates/skills/python-testing-patterns/SKILL.md +907 -0
- package/templates/skills/rag-implementation/SKILL.md +403 -0
- package/templates/skills/react-modernization/SKILL.md +513 -0
- package/templates/skills/react-native-architecture/SKILL.md +671 -0
- package/templates/skills/react-state-management/SKILL.md +429 -0
- package/templates/skills/risk-metrics-calculation/SKILL.md +555 -0
- package/templates/skills/rust-async-patterns/SKILL.md +517 -0
- package/templates/skills/secrets-management/SKILL.md +346 -0
- package/templates/skills/security-requirement-extraction/SKILL.md +677 -0
- package/templates/skills/shellcheck-configuration/SKILL.md +454 -0
- package/templates/skills/similarity-search-patterns/SKILL.md +558 -0
- package/templates/skills/slo-implementation/SKILL.md +329 -0
- package/templates/skills/sql-optimization-patterns/SKILL.md +493 -0
- package/templates/skills/stripe-integration/SKILL.md +442 -0
- package/templates/skills/tailwind-design-system/SKILL.md +666 -0
- package/templates/skills/temporal-python-testing/SKILL.md +158 -0
- package/templates/skills/temporal-python-testing/resources/integration-testing.md +455 -0
- package/templates/skills/temporal-python-testing/resources/local-setup.md +553 -0
- package/templates/skills/temporal-python-testing/resources/replay-testing.md +462 -0
- package/templates/skills/temporal-python-testing/resources/unit-testing.md +328 -0
- package/templates/skills/terraform-module-library/SKILL.md +249 -0
- package/templates/skills/terraform-module-library/references/aws-modules.md +63 -0
- package/templates/skills/threat-mitigation-mapping/SKILL.md +745 -0
- package/templates/skills/track-management/SKILL.md +593 -0
- package/templates/skills/typescript-advanced-types/SKILL.md +717 -0
- package/templates/skills/uv-package-manager/SKILL.md +831 -0
- package/templates/skills/vector-index-tuning/SKILL.md +521 -0
- package/templates/skills/wcag-audit-patterns/SKILL.md +555 -0
- package/templates/skills/workflow-orchestration-patterns/SKILL.md +316 -0
- package/templates/skills/workflow-patterns/SKILL.md +623 -0
- package/templates/agents/game-developer.agent.md +0 -57
- package/templates/agents/kubernetes-specialist.agent.md +0 -56
- package/templates/agents/market-researcher.agent.md +0 -47
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# Entity Framework Core Best Practices
|
|
2
|
+
|
|
3
|
+
Performance optimization and best practices for EF Core in production applications.
|
|
4
|
+
|
|
5
|
+
## Query Optimization
|
|
6
|
+
|
|
7
|
+
### 1. Use AsNoTracking for Read-Only Queries
|
|
8
|
+
|
|
9
|
+
```csharp
|
|
10
|
+
// ✅ Good - No change tracking overhead
|
|
11
|
+
var products = await _context.Products
|
|
12
|
+
.AsNoTracking()
|
|
13
|
+
.Where(p => p.CategoryId == categoryId)
|
|
14
|
+
.ToListAsync(ct);
|
|
15
|
+
|
|
16
|
+
// ❌ Bad - Unnecessary tracking for read-only data
|
|
17
|
+
var products = await _context.Products
|
|
18
|
+
.Where(p => p.CategoryId == categoryId)
|
|
19
|
+
.ToListAsync(ct);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Select Only Needed Columns
|
|
23
|
+
|
|
24
|
+
```csharp
|
|
25
|
+
// ✅ Good - Project to DTO
|
|
26
|
+
var products = await _context.Products
|
|
27
|
+
.AsNoTracking()
|
|
28
|
+
.Where(p => p.CategoryId == categoryId)
|
|
29
|
+
.Select(p => new ProductDto
|
|
30
|
+
{
|
|
31
|
+
Id = p.Id,
|
|
32
|
+
Name = p.Name,
|
|
33
|
+
Price = p.Price
|
|
34
|
+
})
|
|
35
|
+
.ToListAsync(ct);
|
|
36
|
+
|
|
37
|
+
// ❌ Bad - Fetching all columns
|
|
38
|
+
var products = await _context.Products
|
|
39
|
+
.Where(p => p.CategoryId == categoryId)
|
|
40
|
+
.ToListAsync(ct);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 3. Avoid N+1 Queries with Eager Loading
|
|
44
|
+
|
|
45
|
+
```csharp
|
|
46
|
+
// ✅ Good - Single query with Include
|
|
47
|
+
var orders = await _context.Orders
|
|
48
|
+
.AsNoTracking()
|
|
49
|
+
.Include(o => o.Items)
|
|
50
|
+
.ThenInclude(i => i.Product)
|
|
51
|
+
.Where(o => o.CustomerId == customerId)
|
|
52
|
+
.ToListAsync(ct);
|
|
53
|
+
|
|
54
|
+
// ❌ Bad - N+1 queries (lazy loading)
|
|
55
|
+
var orders = await _context.Orders
|
|
56
|
+
.Where(o => o.CustomerId == customerId)
|
|
57
|
+
.ToListAsync(ct);
|
|
58
|
+
|
|
59
|
+
foreach (var order in orders)
|
|
60
|
+
{
|
|
61
|
+
// Each iteration triggers a separate query!
|
|
62
|
+
var items = order.Items.ToList();
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 4. Use Split Queries for Large Includes
|
|
67
|
+
|
|
68
|
+
```csharp
|
|
69
|
+
// ✅ Good - Prevents cartesian explosion
|
|
70
|
+
var orders = await _context.Orders
|
|
71
|
+
.AsNoTracking()
|
|
72
|
+
.Include(o => o.Items)
|
|
73
|
+
.Include(o => o.Payments)
|
|
74
|
+
.Include(o => o.ShippingHistory)
|
|
75
|
+
.AsSplitQuery() // Executes as multiple queries
|
|
76
|
+
.Where(o => o.CustomerId == customerId)
|
|
77
|
+
.ToListAsync(ct);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 5. Use Compiled Queries for Hot Paths
|
|
81
|
+
|
|
82
|
+
```csharp
|
|
83
|
+
public class ProductRepository
|
|
84
|
+
{
|
|
85
|
+
// Compile once, reuse many times
|
|
86
|
+
private static readonly Func<AppDbContext, string, Task<Product?>> GetByIdQuery =
|
|
87
|
+
EF.CompileAsyncQuery((AppDbContext ctx, string id) =>
|
|
88
|
+
ctx.Products.AsNoTracking().FirstOrDefault(p => p.Id == id));
|
|
89
|
+
|
|
90
|
+
private static readonly Func<AppDbContext, int, IAsyncEnumerable<Product>> GetByCategoryQuery =
|
|
91
|
+
EF.CompileAsyncQuery((AppDbContext ctx, int categoryId) =>
|
|
92
|
+
ctx.Products.AsNoTracking().Where(p => p.CategoryId == categoryId));
|
|
93
|
+
|
|
94
|
+
public Task<Product?> GetByIdAsync(string id, CancellationToken ct)
|
|
95
|
+
=> GetByIdQuery(_context, id);
|
|
96
|
+
|
|
97
|
+
public IAsyncEnumerable<Product> GetByCategoryAsync(int categoryId)
|
|
98
|
+
=> GetByCategoryQuery(_context, categoryId);
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Batch Operations
|
|
103
|
+
|
|
104
|
+
### 6. Use ExecuteUpdate/ExecuteDelete (.NET 7+)
|
|
105
|
+
|
|
106
|
+
```csharp
|
|
107
|
+
// ✅ Good - Single SQL UPDATE
|
|
108
|
+
await _context.Products
|
|
109
|
+
.Where(p => p.CategoryId == oldCategoryId)
|
|
110
|
+
.ExecuteUpdateAsync(s => s
|
|
111
|
+
.SetProperty(p => p.CategoryId, newCategoryId)
|
|
112
|
+
.SetProperty(p => p.UpdatedAt, DateTime.UtcNow),
|
|
113
|
+
ct);
|
|
114
|
+
|
|
115
|
+
// ✅ Good - Single SQL DELETE
|
|
116
|
+
await _context.Products
|
|
117
|
+
.Where(p => p.IsDeleted && p.UpdatedAt < cutoffDate)
|
|
118
|
+
.ExecuteDeleteAsync(ct);
|
|
119
|
+
|
|
120
|
+
// ❌ Bad - Loads all entities into memory
|
|
121
|
+
var products = await _context.Products
|
|
122
|
+
.Where(p => p.CategoryId == oldCategoryId)
|
|
123
|
+
.ToListAsync(ct);
|
|
124
|
+
|
|
125
|
+
foreach (var product in products)
|
|
126
|
+
{
|
|
127
|
+
product.CategoryId = newCategoryId;
|
|
128
|
+
}
|
|
129
|
+
await _context.SaveChangesAsync(ct);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 7. Bulk Insert with EFCore.BulkExtensions
|
|
133
|
+
|
|
134
|
+
```csharp
|
|
135
|
+
// Using EFCore.BulkExtensions package
|
|
136
|
+
var products = GenerateLargeProductList();
|
|
137
|
+
|
|
138
|
+
// ✅ Good - Bulk insert (much faster for large datasets)
|
|
139
|
+
await _context.BulkInsertAsync(products, ct);
|
|
140
|
+
|
|
141
|
+
// ❌ Bad - Individual inserts
|
|
142
|
+
foreach (var product in products)
|
|
143
|
+
{
|
|
144
|
+
_context.Products.Add(product);
|
|
145
|
+
}
|
|
146
|
+
await _context.SaveChangesAsync(ct);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Connection Management
|
|
150
|
+
|
|
151
|
+
### 8. Configure Connection Pooling
|
|
152
|
+
|
|
153
|
+
```csharp
|
|
154
|
+
services.AddDbContext<AppDbContext>(options =>
|
|
155
|
+
{
|
|
156
|
+
options.UseSqlServer(connectionString, sqlOptions =>
|
|
157
|
+
{
|
|
158
|
+
sqlOptions.EnableRetryOnFailure(
|
|
159
|
+
maxRetryCount: 3,
|
|
160
|
+
maxRetryDelay: TimeSpan.FromSeconds(10),
|
|
161
|
+
errorNumbersToAdd: null);
|
|
162
|
+
|
|
163
|
+
sqlOptions.CommandTimeout(30);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// Performance settings
|
|
167
|
+
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
|
168
|
+
|
|
169
|
+
// Development only
|
|
170
|
+
if (env.IsDevelopment())
|
|
171
|
+
{
|
|
172
|
+
options.EnableSensitiveDataLogging();
|
|
173
|
+
options.EnableDetailedErrors();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 9. Use DbContext Pooling
|
|
179
|
+
|
|
180
|
+
```csharp
|
|
181
|
+
// ✅ Good - Context pooling (reduces allocation overhead)
|
|
182
|
+
services.AddDbContextPool<AppDbContext>(options =>
|
|
183
|
+
{
|
|
184
|
+
options.UseSqlServer(connectionString);
|
|
185
|
+
}, poolSize: 128);
|
|
186
|
+
|
|
187
|
+
// Instead of AddDbContext
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Concurrency and Transactions
|
|
191
|
+
|
|
192
|
+
### 10. Handle Concurrency with Row Versioning
|
|
193
|
+
|
|
194
|
+
```csharp
|
|
195
|
+
public class Product
|
|
196
|
+
{
|
|
197
|
+
public string Id { get; set; }
|
|
198
|
+
public string Name { get; set; }
|
|
199
|
+
|
|
200
|
+
[Timestamp]
|
|
201
|
+
public byte[] RowVersion { get; set; } // SQL Server rowversion
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Or with Fluent API
|
|
205
|
+
builder.Property(p => p.RowVersion)
|
|
206
|
+
.IsRowVersion();
|
|
207
|
+
|
|
208
|
+
// Handle concurrency conflicts
|
|
209
|
+
try
|
|
210
|
+
{
|
|
211
|
+
await _context.SaveChangesAsync(ct);
|
|
212
|
+
}
|
|
213
|
+
catch (DbUpdateConcurrencyException ex)
|
|
214
|
+
{
|
|
215
|
+
var entry = ex.Entries.Single();
|
|
216
|
+
var databaseValues = await entry.GetDatabaseValuesAsync(ct);
|
|
217
|
+
|
|
218
|
+
if (databaseValues == null)
|
|
219
|
+
{
|
|
220
|
+
// Entity was deleted
|
|
221
|
+
throw new NotFoundException("Product was deleted by another user");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Client wins - overwrite database values
|
|
225
|
+
entry.OriginalValues.SetValues(databaseValues);
|
|
226
|
+
await _context.SaveChangesAsync(ct);
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### 11. Use Explicit Transactions When Needed
|
|
231
|
+
|
|
232
|
+
```csharp
|
|
233
|
+
await using var transaction = await _context.Database.BeginTransactionAsync(ct);
|
|
234
|
+
|
|
235
|
+
try
|
|
236
|
+
{
|
|
237
|
+
// Multiple operations
|
|
238
|
+
_context.Orders.Add(order);
|
|
239
|
+
await _context.SaveChangesAsync(ct);
|
|
240
|
+
|
|
241
|
+
await _context.OrderItems.AddRangeAsync(items, ct);
|
|
242
|
+
await _context.SaveChangesAsync(ct);
|
|
243
|
+
|
|
244
|
+
await _paymentService.ProcessAsync(order.Id, ct);
|
|
245
|
+
|
|
246
|
+
await transaction.CommitAsync(ct);
|
|
247
|
+
}
|
|
248
|
+
catch
|
|
249
|
+
{
|
|
250
|
+
await transaction.RollbackAsync(ct);
|
|
251
|
+
throw;
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Indexing Strategy
|
|
256
|
+
|
|
257
|
+
### 12. Create Indexes for Query Patterns
|
|
258
|
+
|
|
259
|
+
```csharp
|
|
260
|
+
public class ProductConfiguration : IEntityTypeConfiguration<Product>
|
|
261
|
+
{
|
|
262
|
+
public void Configure(EntityTypeBuilder<Product> builder)
|
|
263
|
+
{
|
|
264
|
+
// Unique index
|
|
265
|
+
builder.HasIndex(p => p.Sku)
|
|
266
|
+
.IsUnique();
|
|
267
|
+
|
|
268
|
+
// Composite index for common query patterns
|
|
269
|
+
builder.HasIndex(p => new { p.CategoryId, p.Name });
|
|
270
|
+
|
|
271
|
+
// Filtered index (SQL Server)
|
|
272
|
+
builder.HasIndex(p => p.Price)
|
|
273
|
+
.HasFilter("[IsDeleted] = 0");
|
|
274
|
+
|
|
275
|
+
// Include columns for covering index
|
|
276
|
+
builder.HasIndex(p => p.CategoryId)
|
|
277
|
+
.IncludeProperties(p => new { p.Name, p.Price });
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Common Anti-Patterns to Avoid
|
|
283
|
+
|
|
284
|
+
### ❌ Calling ToList() Too Early
|
|
285
|
+
|
|
286
|
+
```csharp
|
|
287
|
+
// ❌ Bad - Materializes all products then filters in memory
|
|
288
|
+
var products = _context.Products.ToList()
|
|
289
|
+
.Where(p => p.Price > 100);
|
|
290
|
+
|
|
291
|
+
// ✅ Good - Filter in SQL
|
|
292
|
+
var products = await _context.Products
|
|
293
|
+
.Where(p => p.Price > 100)
|
|
294
|
+
.ToListAsync(ct);
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### ❌ Using Contains with Large Collections
|
|
298
|
+
|
|
299
|
+
```csharp
|
|
300
|
+
// ❌ Bad - Generates massive IN clause
|
|
301
|
+
var ids = GetThousandsOfIds();
|
|
302
|
+
var products = await _context.Products
|
|
303
|
+
.Where(p => ids.Contains(p.Id))
|
|
304
|
+
.ToListAsync(ct);
|
|
305
|
+
|
|
306
|
+
// ✅ Good - Use temp table or batch queries
|
|
307
|
+
var products = new List<Product>();
|
|
308
|
+
foreach (var batch in ids.Chunk(100))
|
|
309
|
+
{
|
|
310
|
+
var batchResults = await _context.Products
|
|
311
|
+
.Where(p => batch.Contains(p.Id))
|
|
312
|
+
.ToListAsync(ct);
|
|
313
|
+
products.AddRange(batchResults);
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### ❌ String Concatenation in Queries
|
|
318
|
+
|
|
319
|
+
```csharp
|
|
320
|
+
// ❌ Bad - Can't use index
|
|
321
|
+
var products = await _context.Products
|
|
322
|
+
.Where(p => (p.FirstName + " " + p.LastName).Contains(searchTerm))
|
|
323
|
+
.ToListAsync(ct);
|
|
324
|
+
|
|
325
|
+
// ✅ Good - Use computed column with index
|
|
326
|
+
builder.Property(p => p.FullName)
|
|
327
|
+
.HasComputedColumnSql("[FirstName] + ' ' + [LastName]");
|
|
328
|
+
builder.HasIndex(p => p.FullName);
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Monitoring and Diagnostics
|
|
332
|
+
|
|
333
|
+
```csharp
|
|
334
|
+
// Log slow queries
|
|
335
|
+
services.AddDbContext<AppDbContext>(options =>
|
|
336
|
+
{
|
|
337
|
+
options.UseSqlServer(connectionString);
|
|
338
|
+
|
|
339
|
+
options.LogTo(
|
|
340
|
+
filter: (eventId, level) => eventId.Id == CoreEventId.QueryExecutionPlanned.Id,
|
|
341
|
+
logger: (eventData) =>
|
|
342
|
+
{
|
|
343
|
+
if (eventData is QueryExpressionEventData queryData)
|
|
344
|
+
{
|
|
345
|
+
var duration = queryData.Duration;
|
|
346
|
+
if (duration > TimeSpan.FromSeconds(1))
|
|
347
|
+
{
|
|
348
|
+
_logger.LogWarning("Slow query detected: {Duration}ms - {Query}",
|
|
349
|
+
duration.TotalMilliseconds,
|
|
350
|
+
queryData.Expression);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
```
|