Entity Framework Core: āļāļēāļĢāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāđāļĨāļ°āđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”āđƒāļ™āļ›āļĩ 2026

āļ„āļđāđˆāļĄāļ·āļ­āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž Entity Framework Core 10 āļšāļ™ .NET 10 āđ€āļĢāļĩāļĒāļ™āļĢāļđāđ‰ AsNoTracking, compiled queries, batch updates, split queries āđāļĨāļ°āļ•āļąāļ§āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ LeftJoin

Entity Framework Core Performance Optimization

Entity Framework Core 10 āļ‹āļķāđˆāļ‡āđ€āļ›āļīāļ”āļ•āļąāļ§āļžāļĢāđ‰āļ­āļĄāļāļąāļš .NET 10 LTS āđƒāļ™āđ€āļ”āļ·āļ­āļ™āļžāļĪāļĻāļˆāļīāļāļēāļĒāļ™ 2025 āļ™āļģāđ€āļŠāļ™āļ­āļ•āļąāļ§āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ LeftJoin āļāļēāļĢāļ„āđ‰āļ™āļŦāļēāđ€āļ§āļāđ€āļ•āļ­āļĢāđŒ named query filters āđāļĨāļ°āļāļēāļĢāļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āļāļēāļĢāđāļ›āļĨ SQL āļ­āļĒāđˆāļēāļ‡āļĄāļĩāļ™āļąāļĒāļŠāļģāļ„āļąāļ āļšāļ—āļ„āļ§āļēāļĄāļ™āļĩāđ‰āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”āļ‚āļ­āļ‡ EF Core āļ—āļĩāđˆāļŠāđˆāļ‡āļœāļĨāđ‚āļ”āļĒāļ•āļĢāļ‡āļ•āđˆāļ­āļ„āļ§āļēāļĄāđ€āļĢāđ‡āļ§āđƒāļ™āļāļēāļĢ query āļāļēāļĢāļˆāļąāļ”āļŠāļĢāļĢāļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģ āđāļĨāļ°āļ„āļ§āļēāļĄāļŠāļēāļĄāļēāļĢāļ–āđƒāļ™āļāļēāļĢāļ›āļĢāļąāļšāļ‚āļ™āļēāļ”āđƒāļ™āļŠāļ āļēāļžāđāļ§āļ”āļĨāđ‰āļ­āļĄ production

EF Core 10 āļ—āļģāļ‡āļēāļ™āļšāļ™ .NET 10 āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™

EF Core 10 āđ€āļ›āđ‡āļ™āđ€āļ§āļ­āļĢāđŒāļŠāļąāļ™ Long-Term Support āļ—āļĩāđˆāđ„āļ”āđ‰āļĢāļąāļšāļāļēāļĢāļŠāļ™āļąāļšāļŠāļ™āļļāļ™āļˆāļ™āļ–āļķāļ‡āđ€āļ”āļ·āļ­āļ™āļžāļĪāļĻāļˆāļīāļāļēāļĒāļ™ 2028 āļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰ SDK āđāļĨāļ° runtime āļ‚āļ­āļ‡ .NET 10 āđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™āļ—āļĩāđˆāļĒāļąāļ‡āļ„āļ‡āđƒāļŠāđ‰ .NET 8 āļ„āļ§āļĢāđ€āļĨāļ·āļ­āļāđƒāļŠāđ‰ EF Core 8 (LTS) āļˆāļ™āļāļ§āđˆāļēāļˆāļ°āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāļĒāđ‰āļēāļĒāļĢāļ°āļšāļšāđ€āļŠāļĢāđ‡āļˆāļŠāļīāđ‰āļ™

Query Tracking: āđ€āļĄāļ·āđˆāļ­āđƒāļ”āļ„āļ§āļĢāļ›āļīāļ”āļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™āđāļĨāļ°āđ€āļžāļĢāļēāļ°āđ€āļŦāļ•āļļāđƒāļ”

āļ—āļļāļāļāļēāļĢāđ€āļĢāļĩāļĒāļāđƒāļŠāđ‰ DbSet<T> āļˆāļ°āđāļ™āļš entity āļ—āļĩāđˆāļŠāđˆāļ‡āļāļĨāļąāļšāđ€āļ‚āđ‰āļēāļāļąāļš change tracker āđ‚āļ”āļĒāļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ Tracker āļ™āļĩāđ‰āļˆāļ°āđ€āļāđ‡āļš snapshot āļ‚āļ­āļ‡āļ„āđˆāļē property āđ€āļ”āļīāļĄ āļ„āļģāļ™āļ§āļ“āļ„āļ§āļēāļĄāđāļ•āļāļ•āđˆāļēāļ‡āđ€āļĄāļ·āđˆāļ­āđ€āļĢāļĩāļĒāļ SaveChanges āđāļĨāļ°āđāļāđ‰āđ„āļ‚āļ‚āđ‰āļ­āļ‚āļąāļ”āđāļĒāđ‰āļ‡āļ‚āļ­āļ‡ identity āļ‚āđ‰āļēāļĄ navigation āļ•āđˆāļēāļ‡āđ† āļ„āđˆāļēāđƒāļŠāđ‰āļˆāđˆāļēāļĒāļ™āļĩāđ‰āđ„āļĄāđˆāļˆāļģāđ€āļ›āđ‡āļ™āđ€āļĄāļ·āđˆāļ­āļ‚āđ‰āļ­āļĄāļđāļĨāļ–āļđāļāļŠāđˆāļ‡āļ•āļĢāļ‡āđ„āļ›āļĒāļąāļ‡ API response āļŦāļĢāļ·āļ­ view model āđāļšāļšāļ­āđˆāļēāļ™āļ­āļĒāđˆāļēāļ‡āđ€āļ”āļĩāļĒāļ§

ProductRepository.cscsharp
public async Task<List<ProductDto>> GetActiveByCategoryAsync(
    int categoryId, CancellationToken ct)
{
    return await _context.Products
        .AsNoTracking()              // āļ‚āđ‰āļēāļĄ change tracker āļ—āļąāđ‰āļ‡āļŦāļĄāļ”
        .Where(p => p.CategoryId == categoryId && p.IsActive)
        .OrderBy(p => p.Name)
        .Select(p => new ProductDto   // āļ‰āļēāļĒāļ‚āđ‰āļ­āļĄāļđāļĨāđ€āļ›āđ‡āļ™ DTO āļ—āļĩāđˆāļĢāļ°āļ”āļąāļšāļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨ
        {
            Id = p.Id,
            Name = p.Name,
            Price = p.Price
        })
        .ToListAsync(ct);
}

AsNoTracking āļ‚āļˆāļąāļ”āļ„āđˆāļēāđƒāļŠāđ‰āļˆāđˆāļēāļĒāđƒāļ™āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡ snapshot āđāļĨāļ°āļāļēāļĢāđāļāđ‰āđ„āļ‚ identity āļ‚āļ­āļ‡āđāļ•āđˆāļĨāļ° entity āđ€āļĄāļ·āđˆāļ­āđƒāļŠāđ‰āļĢāđˆāļ§āļĄāļāļąāļš Select āļˆāļ°āļĄāļĩāđ€āļžāļĩāļĒāļ‡āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ—āļĩāđˆāļˆāļģāđ€āļ›āđ‡āļ™āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™āļ—āļĩāđˆāļ–āļđāļāļŠāđˆāļ‡āļœāđˆāļēāļ™āđ€āļ„āļĢāļ·āļ­āļ‚āđˆāļēāļĒ āļŠāļģāļŦāļĢāļąāļšāļ•āļēāļĢāļēāļ‡āļ—āļĩāđˆāļĄāļĩ 50,000 āđāļ–āļ§ āļĢāļđāļ›āđāļšāļšāļ™āļĩāđ‰āļŠāļēāļĄāļēāļĢāļ–āļĨāļ”āļāļēāļĢāļˆāļąāļ”āļŠāļĢāļĢāļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģāđ„āļ”āđ‰ 40-60% āđ€āļĄāļ·āđˆāļ­āđ€āļ—āļĩāļĒāļšāļāļąāļšāļāļēāļĢ query full-entity āđāļšāļšāļĄāļĩ tracking

āļŠāļģāļŦāļĢāļąāļš context āļ—āļĩāđˆāđ„āļĄāđˆāđ€āļ„āļĒāđāļāđ‰āđ„āļ‚āļ‚āđ‰āļ­āļĄāļđāļĨ āđƒāļŦāđ‰āļ•āļąāđ‰āļ‡āļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āļ•āļ­āļ™āļĨāļ‡āļ—āļ°āđ€āļšāļĩāļĒāļ™:

Program.cscsharp
builder.Services.AddDbContext<CatalogContext>(options =>
    options.UseSqlServer(connectionString)
           .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking));

Split Queries āđ€āļžāļ·āđˆāļ­āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāļĢāļ°āđ€āļšāļīāļ”āđāļšāļš Cartesian

āļāļēāļĢāđ‚āļŦāļĨāļ” entity āļ—āļĩāđˆāļĄāļĩ collection navigation āļŦāļĨāļēāļĒāļ•āļąāļ§āļœāđˆāļēāļ™ Include āļˆāļ°āļŠāļĢāđ‰āļēāļ‡āļ„āļģāļŠāļąāđˆāļ‡ SQL āđ€āļ”āļĩāļĒāļ§āļ—āļĩāđˆāļĄāļĩ JOIN āđ€āļĄāļ·āđˆāļ­āļĄāļĩāļāļēāļĢāđ‚āļŦāļĨāļ”āļŠāļ­āļ‡āļ„āļ­āļĨāđ€āļĨāļāļŠāļąāļ™āļ‚āļķāđ‰āļ™āđ„āļ›āļžāļĢāđ‰āļ­āļĄāļāļąāļ™ āļœāļĨāļĨāļąāļžāļ˜āđŒāļˆāļ°āļ‚āļĒāļēāļĒāļ•āļąāļ§āđ€āļ›āđ‡āļ™āļœāļĨāļ„āļđāļ“ Cartesian āļ‚āļ­āļ‡āļ„āļ­āļĨāđ€āļĨāļāļŠāļąāļ™āļ•āđˆāļēāļ‡āđ† āļ—āļģāđƒāļŦāđ‰āļ‚āđ‰āļ­āļĄāļđāļĨāđāļ–āļ§āļŦāļĨāļąāļāļ–āļđāļāļ—āļģāļ‹āđ‰āļģāđƒāļ™āļ—āļļāļāļāļēāļĢāļĢāļ§āļĄāļāļąāļ™

OrderRepository.cscsharp
public async Task<Order?> GetWithDetailsAsync(int orderId, CancellationToken ct)
{
    return await _context.Orders
        .AsSplitQuery()              // SQL āļŦāļ™āļķāđˆāļ‡āļ„āļģāļŠāļąāđˆāļ‡āļ•āđˆāļ­āļŦāļ™āļķāđˆāļ‡ Include
        .Include(o => o.Items)
            .ThenInclude(i => i.Product)
        .Include(o => o.Payments)
        .Include(o => o.ShippingEvents)
        .FirstOrDefaultAsync(o => o.Id == orderId, ct);
}

AsSplitQuery āđāļšāđˆāļ‡āļāļēāļĢāđ‚āļŦāļĨāļ”āđ€āļ›āđ‡āļ™āļ„āļģāļŠāļąāđˆāļ‡ SQL āđāļĒāļāļāļąāļ™āļŠāļģāļŦāļĢāļąāļšāđāļ•āđˆāļĨāļ° navigation āļ‚āđ‰āļ­āđāļĨāļāđ€āļ›āļĨāļĩāđˆāļĒāļ™āļ„āļ·āļ­: āļŦāļĨāļēāļĒ round-trip āđāļ—āļ™āļ—āļĩāđˆāļˆāļ°āđ€āļ›āđ‡āļ™āļŦāļ™āļķāđˆāļ‡ āđāļ•āđˆāđāļ•āđˆāļĨāļ°āļŠāļļāļ”āļœāļĨāļĨāļąāļžāļ˜āđŒāļˆāļ°āļĄāļĩāļ‚āļ™āļēāļ”āđ€āļĨāđ‡āļāđāļĨāļ°āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļ›āļąāļāļŦāļēāļāļēāļĢāļ—āļģāļ‹āđ‰āļģāđāļ–āļ§ EF Core 10 āļĒāļąāļ‡āđāļāđ‰āđ„āļ‚āļ„āļ§āļēāļĄāđ„āļĄāđˆāļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļ‚āļ­āļ‡āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļšāļ—āļĩāđˆāļĄāļĩāļĄāļēāļ™āļēāļ™āđƒāļ™ split queries āļ—āļģāđƒāļŦāđ‰āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļš subquery āļ•āļĢāļ‡āļāļąāļš query āļŦāļĨāļąāļ

āđ€āļĄāļ·āđˆāļ­āđƒāļ”āļ„āļ§āļĢāđƒāļŠāđ‰ single query

Single query āļĒāļąāļ‡āļ„āļ‡āđ€āļŦāļĄāļēāļ°āļŠāļĄāļāļ§āđˆāļēāđ€āļĄāļ·āđˆāļ­āđ‚āļŦāļĨāļ” collection navigation āđ€āļžāļĩāļĒāļ‡āļŦāļ™āļķāđˆāļ‡āļ•āļąāļ§ āļŦāļĢāļ·āļ­āđ€āļĄāļ·āđˆāļ­ latency āļ‚āļ­āļ‡ round-trip āļŠāļđāļ‡ (āļāļēāļĢāđ€āļĢāļĩāļĒāļāļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļ‚āđ‰āļēāļĄāļ āļđāļĄāļīāļ āļēāļ„) āļ„āļ§āļĢāļ—āļģ benchmark āļ—āļąāđ‰āļ‡āļŠāļ­āļ‡āđ‚āļŦāļĄāļ”āļŠāļģāļŦāļĢāļąāļšāļĢāļđāļ›āđāļšāļšāļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡āđ€āļ‰āļžāļēāļ°āļāđˆāļ­āļ™āļ•āļąāļ”āļŠāļīāļ™āđƒāļˆ

āļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāđāļšāļš Batch āļ”āđ‰āļ§āļĒ ExecuteUpdate āđāļĨāļ° ExecuteDelete

āđ€āļ§āļīāļĢāđŒāļāđ‚āļŸāļĨāļ§āđŒ EF āđāļšāļšāļ”āļąāđ‰āļ‡āđ€āļ”āļīāļĄāļˆāļ°āđ‚āļŦāļĨāļ” entity āđāļāđ‰āđ„āļ‚ property āđāļĨāđ‰āļ§āđ€āļĢāļĩāļĒāļ SaveChanges āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāļˆāļģāļ™āļ§āļ™āļĄāļēāļāļ—āļĩāđˆāļŠāđˆāļ‡āļœāļĨāļāļĢāļ°āļ—āļšāļ•āđˆāļ­āļŦāļĨāļēāļĒāļžāļąāļ™āđāļ–āļ§ āļ§āļīāļ˜āļĩāļ™āļĩāđ‰āļŠāļĢāđ‰āļēāļ‡ instance āļ—āļĩāđˆāļ–āļđāļāļ•āļīāļ”āļ•āļēāļĄāļŦāļĨāļēāļĒāļžāļąāļ™āļ•āļąāļ§āđāļĨāļ°āļ„āļģāļŠāļąāđˆāļ‡ UPDATE āđāļĒāļāļāļąāļ™ EF Core 7 āđ€āļ›āļīāļ”āļ•āļąāļ§ ExecuteUpdateAsync āđāļĨāļ° ExecuteDeleteAsync āđ€āļžāļ·āđˆāļ­āļŠāđˆāļ‡āļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāđ€āļ›āđ‡āļ™āļ„āļģāļŠāļąāđˆāļ‡ SQL āđ€āļ”āļĩāļĒāļ§ EF Core 10 āļ—āļģāđƒāļŦāđ‰ API āļ‡āđˆāļēāļĒāļ‚āļķāđ‰āļ™āļ­āļĩāļāđ‚āļ”āļĒāļĢāļąāļš lambda āļ˜āļĢāļĢāļĄāļ”āļēāđāļ—āļ™ expression tree

PromotionService.cscsharp
public async Task ApplySeasonalDiscountAsync(
    int categoryId, decimal discountPercent, CancellationToken ct)
{
    var affected = await _context.Products
        .Where(p => p.CategoryId == categoryId && p.IsActive)
        .ExecuteUpdateAsync(s =>
        {
            s.SetProperty(p => p.Price, p => p.Price * (1 - discountPercent / 100));
            s.SetProperty(p => p.LastModified, DateTime.UtcNow);
        }, ct);

    // affected = āļˆāļģāļ™āļ§āļ™āđāļ–āļ§āļ—āļĩāđˆāļ–āļđāļāļ­āļąāļ›āđ€āļ”āļ•
}

āļ„āļģāļŠāļąāđˆāļ‡āļ™āļĩāđ‰āļ–āļđāļāđāļ›āļĨāđ€āļ›āđ‡āļ™ UPDATE ... SET ... WHERE āđ€āļ”āļĩāļĒāļ§ āđ„āļĄāđˆāļĄāļĩ entity āđƒāļ”āļ–āļđāļāđ‚āļŦāļĨāļ”āđ€āļ‚āđ‰āļēāļŦāļ™āđˆāļ§āļĒāļ„āļ§āļēāļĄāļˆāļģ āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ­āļąāļ›āđ€āļ”āļ• 10,000 āđāļ–āļ§ āđ€āļ§āļĨāļēāđƒāļ™āļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāļĨāļ”āļĨāļ‡āļˆāļēāļāļŦāļĨāļēāļĒāļ§āļīāļ™āļēāļ—āļĩ (āđāļšāļš tracked) āđ€āļŦāļĨāļ·āļ­āđ€āļžāļĩāļĒāļ‡āļĄāļīāļĨāļĨāļīāļ§āļīāļ™āļēāļ—āļĩ

āļĢāļđāļ›āđāļšāļšāđ€āļ”āļĩāļĒāļ§āļāļąāļ™āđƒāļŠāđ‰āđ„āļ”āđ‰āļāļąāļšāļāļēāļĢāļĨāļš:

CleanupService.cscsharp
public async Task PurgeExpiredSessionsAsync(CancellationToken ct)
{
    await _context.Sessions
        .Where(s => s.ExpiresAt < DateTime.UtcNow)
        .ExecuteDeleteAsync(ct);
}

āļžāļĢāđ‰āļ­āļĄāļ—āļĩāđˆāļˆāļ°āļžāļīāļŠāļīāļ•āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ .NET āđāļĨāđ‰āļ§āļŦāļĢāļ·āļ­āļĒāļąāļ‡āļ„āļĢāļąāļš?

āļāļķāļāļāļ™āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āđāļšāļšāđ‚āļ•āđ‰āļ•āļ­āļš, flashcards āđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļ•āļąāļ§āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ LeftJoin āđƒāļ™ EF Core 10

āļāđˆāļ­āļ™ EF Core 10 āļāļēāļĢāļ—āļģ LEFT JOIN āļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰āļāļēāļĢāļĢāļ§āļĄ GroupJoin, SelectMany āđāļĨāļ° DefaultIfEmpty āđƒāļ™āļĢāļđāļ›āđāļšāļšāđ€āļ‰āļžāļēāļ°āļ—āļĩāđˆāļ™āļąāļāļžāļąāļ’āļ™āļēāļŠāđˆāļ§āļ™āđƒāļŦāļāđˆāļ•āđ‰āļ­āļ‡āļ„āđ‰āļ™āļŦāļēāļ—āļļāļāļ„āļĢāļąāđ‰āļ‡āļ—āļĩāđˆāđƒāļŠāđ‰āļ‡āļēāļ™ EF Core 10 āđ€āļžāļīāđˆāļĄ LeftJoin āđ€āļ›āđ‡āļ™āļ•āļąāļ§āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ LINQ āļĢāļ°āļ”āļąāļšāļŦāļ™āļķāđˆāļ‡

ReportService.cscsharp
public async Task<List<EmployeeReportDto>> GetEmployeeDepartmentReportAsync(
    CancellationToken ct)
{
    return await _context.Employees
        .LeftJoin(
            _context.Departments,
            employee => employee.DepartmentId,
            department => department.Id,
            (employee, department) => new EmployeeReportDto
            {
                FullName = employee.FirstName + " " + employee.LastName,
                Department = department.Name ?? "Unassigned",
                HiredAt = employee.HiredAt
            })
        .OrderBy(r => r.FullName)
        .ToListAsync(ct);
}

SQL āļ—āļĩāđˆāļŠāļĢāđ‰āļēāļ‡āļ‚āļķāđ‰āļ™āđƒāļŠāđ‰ clause LEFT JOIN āļĄāļēāļ•āļĢāļāļēāļ™ āļ•āļąāļ§āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ RightJoin āļāđ‡āļĄāļĩāđƒāļŦāđ‰āđƒāļŠāđ‰āļ‡āļēāļ™āđ€āļŠāđˆāļ™āļāļąāļ™ āļ•āļąāļ§āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāļ—āļąāđ‰āļ‡āļŠāļ­āļ‡āļ‚āļˆāļąāļ”āļŦāđˆāļ§āļ‡āđ‚āļ‹āđˆāļŠāļēāļĄāđ€āļĄāļ˜āļ­āļ”āļ—āļĩāđˆāļĒāļēāļ§āđ€āļŦāļĒāļĩāļĒāļ”āļ‹āļķāđˆāļ‡āļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰āļāđˆāļ­āļ™āļŦāļ™āđ‰āļēāļ™āļĩāđ‰

Named Query Filters āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļāļĢāļ­āļ‡āļŦāļĨāļēāļĒāļ§āļąāļ•āļ–āļļāļ›āļĢāļ°āļŠāļ‡āļ„āđŒ

Global query filters āļ–āļđāļāļˆāļģāļāļąāļ”āđƒāļŦāđ‰āļĄāļĩāđ€āļžāļĩāļĒāļ‡āļŦāļ™āļķāđˆāļ‡ filter āļ•āđˆāļ­āļŦāļ™āļķāđˆāļ‡āļ›āļĢāļ°āđ€āļ āļ— entity āļ•āļąāđ‰āļ‡āđāļ•āđˆ EF Core 2.0 āđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™āļ—āļĩāđˆāđƒāļŠāđ‰āļ—āļąāđ‰āļ‡ soft-delete āđāļĨāļ° multi-tenancy āļ•āđ‰āļ­āļ‡āļĢāļ§āļĄāđ€āļ‡āļ·āđˆāļ­āļ™āđ„āļ‚āđ€āļ›āđ‡āļ™āļ™āļīāļžāļˆāļ™āđŒāđ€āļ”āļĩāļĒāļ§āđāļĨāļ°āđ„āļĄāđˆāļŠāļēāļĄāļēāļĢāļ–āļ›āļīāļ”āļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™āđāļšāļšāđ€āļĨāļ·āļ­āļāđ„āļ”āđ‰ EF Core 10 āđ€āļ›āļīāļ”āļ•āļąāļ§ named query filters

AppDbContext.cscsharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Invoice>()
        .HasQueryFilter("SoftDelete", i => !i.IsDeleted)
        .HasQueryFilter("Tenant", i => i.TenantId == _tenantId);
}

Endpoint āļŠāļģāļŦāļĢāļąāļšāļœāļđāđ‰āļ”āļđāđāļĨāļĢāļ°āļšāļšāļŠāļēāļĄāļēāļĢāļ–āļ›āļīāļ” filter soft-delete āđƒāļ™āļ‚āļ“āļ°āļ—āļĩāđˆāļĒāļąāļ‡āļ„āļ‡āļĢāļąāļāļĐāļēāļāļēāļĢāđāļĒāļ tenant āđ„āļ§āđ‰:

InvoiceRepository.cscsharp
public async Task<List<Invoice>> GetAllIncludingDeletedAsync(CancellationToken ct)
{
    return await _context.Invoices
        .IgnoreQueryFilters(["SoftDelete"])  // filter tenant āļĒāļąāļ‡āļ„āļ‡āļ—āļģāļ‡āļēāļ™
        .ToListAsync(ct);
}

āļŠāļīāđˆāļ‡āļ™āļĩāđ‰āļ‚āļˆāļąāļ”āļ„āļ§āļēāļĄāļˆāļģāđ€āļ›āđ‡āļ™āđƒāļ™āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡ extension method āļ‚āļ­āļ‡ IQueryable āđāļšāļšāļāļģāļŦāļ™āļ”āđ€āļ­āļ‡āļ—āļĩāđˆāđ€āļžāļīāđˆāļĄāđ€āļ‡āļ·āđˆāļ­āļ™āđ„āļ‚ filter āļ”āđ‰āļ§āļĒāļ•āļ™āđ€āļ­āļ‡

āļ„āļ§āļēāļĄāļĒāļ·āļ”āļŦāļĒāļļāđˆāļ™āļ‚āļ­āļ‡āļāļēāļĢāđ€āļŠāļ·āđˆāļ­āļĄāļ•āđˆāļ­āđāļĨāļ°āļāļēāļĢāļāļģāļŦāļ™āļ”āļ„āđˆāļē Pooling

āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļŠāļąāđˆāļ§āļ„āļĢāļēāļ§ (āđ€āļ„āļĢāļ·āļ­āļ‚āđˆāļēāļĒāļ‚āļąāļ”āļ‚āđ‰āļ­āļ‡, Azure SQL failover, connection pool āļŦāļĄāļ”) āļ—āļģāđƒāļŦāđ‰āđ€āļāļīāļ” exception āļ—āļĩāđˆāļĄāļąāļāļ—āļģāđƒāļŦāđ‰ pipeline āļ‚āļ­āļ‡ request āļĨāđ‰āļĄāđ€āļŦāļĨāļ§ EF Core āļĄāļĩ logic retry āđƒāļ™āļ•āļąāļ§ āđāļ•āđˆāļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āļ•āđ‰āļ­āļ‡āļĄāļĩāļāļēāļĢāļāļģāļŦāļ™āļ”āļ„āđˆāļēāļ­āļĒāđˆāļēāļ‡āļŠāļąāļ”āđ€āļˆāļ™

Program.cscsharp
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(connectionString, sqlOptions =>
    {
        sqlOptions.EnableRetryOnFailure(
            maxRetryCount: 5,
            maxRetryDelay: TimeSpan.FromSeconds(10),
            errorNumbersToAdd: null);    // retry āļŠāļģāļŦāļĢāļąāļšāļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļŠāļąāđˆāļ§āļ„āļĢāļēāļ§āļ—āļąāđ‰āļ‡āļŦāļĄāļ”
        sqlOptions.CommandTimeout(30);   // timeout āļ„āļģāļŠāļąāđˆāļ‡ 30 āļ§āļīāļ™āļēāļ—āļĩ
    }));

āļžāļēāļĢāļēāļĄāļīāđ€āļ•āļ­āļĢāđŒ pooling āđƒāļ™ connection string āļāđ‡āļĄāļĩāļ„āļ§āļēāļĄāļŠāļģāļ„āļąāļāđ€āļŠāđˆāļ™āļāļąāļ™:

text
Server=db.example.com;Database=AppDb;Min Pool Size=5;Max Pool Size=100;Connection Timeout=15;

Min Pool Size āđ€āļāđ‡āļšāļāļēāļĢāđ€āļŠāļ·āđˆāļ­āļĄāļ•āđˆāļ­āļ—āļĩāđˆāļžāļĢāđ‰āļ­āļĄāđƒāļŠāđ‰āļ‡āļēāļ™āļŠāļģāļŦāļĢāļąāļšāļ—āļĢāļēāļŸāļŸāļīāļāļ—āļĩāđˆāļžāļļāđˆāļ‡āļŠāļđāļ‡ Max Pool Size āļˆāļģāļāļąāļ”āļˆāļģāļ™āļ§āļ™āļāļēāļĢāđ€āļŠāļ·āđˆāļ­āļĄāļ•āđˆāļ­āļ—āļĩāđˆāđ€āļ›āļīāļ”āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āđ€āļžāļ·āđˆāļ­āļ›āđ‰āļ­āļ‡āļāļąāļ™āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļģāļ‡āļēāļ™āļŦāļ™āļąāļāđ€āļāļīāļ™āđ„āļ› āļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ 100 āđ€āļŦāļĄāļēāļ°āļŠāļģāļŦāļĢāļąāļšāđ€āļ§āđ‡āļšāđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™āļŠāđˆāļ§āļ™āđƒāļŦāļāđˆ āđāļ•āđˆāļšāļĢāļīāļāļēāļĢāļ—āļĩāđˆāļĄāļĩ throughput āļŠāļđāļ‡āļ­āļēāļˆāļ•āđ‰āļ­āļ‡āļ›āļĢāļąāļšāđāļ•āđˆāļ‡āļ•āļēāļĄāļ›āļĢāļīāļĄāļēāļ“ query āļžāļĢāđ‰āļ­āļĄāļāļąāļ™āļˆāļĢāļīāļ‡

Logic retry āđāļĨāļ° transaction

Retry āļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļīāđ„āļĄāđˆāļ—āļģāļ‡āļēāļ™āļ āļēāļĒāđƒāļ™ transaction āļ—āļĩāđˆāļœāļđāđ‰āđƒāļŠāđ‰āđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ āđƒāļŦāđ‰āļŦāđˆāļ­ transaction āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āđƒāļ™āļāļĨāļĒāļļāļ—āļ˜āđŒ retry āđāļšāļš manual āđ‚āļ”āļĒāđƒāļŠāđ‰ context.Database.CreateExecutionStrategy().ExecuteAsync(...) āđ€āļžāļ·āđˆāļ­āļˆāļąāļ”āļāļēāļĢāļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļŠāļąāđˆāļ§āļ„āļĢāļēāļ§āđƒāļ™āļŦāļĨāļēāļĒāļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ

āļāļĨāļĒāļļāļ—āļ˜āđŒāļāļēāļĢāļ—āļģ Indexing āđāļĨāļ°āļāļēāļĢāļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒ Query

Migration āļ‚āļ­āļ‡ EF Core āļŠāļēāļĄāļēāļĢāļ–āļāļģāļŦāļ™āļ” index āđāļšāļšāļ›āļĢāļ°āļāļēāļĻāđ„āļ”āđ‰ āđāļ•āđˆāļāļēāļĢāđ€āļĨāļ·āļ­āļāļ„āļ­āļĨāļąāļĄāļ™āđŒāļ—āļĩāđˆāļˆāļ°āļ—āļģ index āļ•āđ‰āļ­āļ‡āļ­āļēāļĻāļąāļĒāļ„āļ§āļēāļĄāđ€āļ‚āđ‰āļēāđƒāļˆāļĢāļđāļ›āđāļšāļš query

AppDbContext.cs - OnModelCreatingcsharp
modelBuilder.Entity<Order>(entity =>
{
    // index āđāļšāļšāļœāļŠāļĄāļŠāļģāļŦāļĢāļąāļšāļĢāļđāļ›āđāļšāļš query āļ—āļĩāđˆāđƒāļŠāđ‰āļšāđˆāļ­āļĒ
    entity.HasIndex(o => new { o.CustomerId, o.Status, o.CreatedAt })
          .HasDatabaseName("IX_Order_Customer_Status_Date");

    // index āđāļšāļšāļĄāļĩāļ•āļąāļ§āļāļĢāļ­āļ‡āļŠāļģāļŦāļĢāļąāļšāļ„āļģāļŠāļąāđˆāļ‡āļ‹āļ·āđ‰āļ­āļ—āļĩāđˆāļĒāļąāļ‡āļ”āļģāđ€āļ™āļīāļ™āļ­āļĒāļđāđˆāđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™
    entity.HasIndex(o => o.Status)
          .HasFilter("[Status] <> 'Cancelled'")
          .HasDatabaseName("IX_Order_ActiveStatus");
});

Index āđāļšāļšāļĄāļĩāļ•āļąāļ§āļāļĢāļ­āļ‡āļŠāđˆāļ§āļĒāļĨāļ”āļ‚āļ™āļēāļ” index āđ‚āļ”āļĒāđ„āļĄāđˆāļĢāļ§āļĄāđāļ–āļ§āļ—āļĩāđˆ query āđ„āļĄāđˆāđ€āļ„āļĒāđ€āļ‚āđ‰āļēāļ–āļķāļ‡ āļŠāļģāļŦāļĢāļąāļšāļ•āļēāļĢāļēāļ‡āļ—āļĩāđˆāļĄāļĩāļ„āļģāļŠāļąāđˆāļ‡āļ‹āļ·āđ‰āļ­āļ—āļĩāđˆāļ–āļđāļāļĒāļāđ€āļĨāļīāļ 80% index āđāļšāļšāļĄāļĩāļ•āļąāļ§āļāļĢāļ­āļ‡āļšāļ™āļŠāļ–āļēāļ™āļ°āļ—āļĩāđˆāļĒāļąāļ‡āļ”āļģāđ€āļ™āļīāļ™āļ­āļĒāļđāđˆāļŠāļēāļĄāļēāļĢāļ–āđ€āļĨāđ‡āļāļāļ§āđˆāļēāļ–āļķāļ‡ 5 āđ€āļ—āđˆāļēāđāļĨāļ°āļŠāđāļāļ™āđ„āļ”āđ‰āđ€āļĢāđ‡āļ§āļāļ§āđˆāļē

āđ€āļžāļ·āđˆāļ­āļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒ SQL āļ—āļĩāđˆāļŠāļĢāđ‰āļēāļ‡āļ‚āļķāđ‰āļ™ āđƒāļŦāđ‰āđ€āļ›āļīāļ” logging āđƒāļ™āļŠāļ āļēāļžāđāļ§āļ”āļĨāđ‰āļ­āļĄ development:

Program.cs (āļŠāļģāļŦāļĢāļąāļš development āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™)csharp
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(connectionString)
           .LogTo(Console.WriteLine, LogLevel.Information)
           .EnableSensitiveDataLogging());

āļ„āļąāļ”āļĨāļ­āļ SQL āļ—āļĩāđˆāļšāļąāļ™āļ—āļķāļāđ„āļ§āđ‰āđ„āļ›āļĒāļąāļ‡ SQL Server Management Studio āđāļĨāļ°āļĢāļąāļ™āļ”āđ‰āļ§āļĒ SET STATISTICS IO ON āđ€āļžāļ·āđˆāļ­āļ•āļĢāļ§āļˆāļŠāļ­āļš logical reads āļŦāļĢāļ·āļ­āđƒāļŠāđ‰ EXPLAIN ANALYZE āļšāļ™ PostgreSQL āļ„āļģāđāļ™āļ°āļ™āļģ index āļ—āļĩāđˆāļ‚āļēāļ”āļŦāļēāļĒāđ„āļ›āļˆāļēāļ query plan āļĄāļąāļāđ€āļœāļĒāđƒāļŦāđ‰āđ€āļŦāđ‡āļ™āđ‚āļ­āļāļēāļŠāđƒāļ™āļāļēāļĢāđ€āļžāļīāđˆāļĄāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļ—āļĩāđˆāļĄāļĩāļœāļĨāļāļĢāļ°āļ—āļšāļŠāļđāļ‡āļŠāļļāļ”

Compiled Queries āļŠāļģāļŦāļĢāļąāļš Hot Paths

Expression tree āļ‚āļ­āļ‡ LINQ āļˆāļ°āļ–āļđāļāđāļĒāļāļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒāđāļĨāļ°āđāļ›āļĨāđ€āļ›āđ‡āļ™ SQL āļ—āļļāļāļ„āļĢāļąāđ‰āļ‡āļ—āļĩāđˆāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ āļŠāļģāļŦāļĢāļąāļš query āļ—āļĩāđˆāļ—āļģāļ‡āļēāļ™āļŦāļĨāļēāļĒāļžāļąāļ™āļ„āļĢāļąāđ‰āļ‡āļ•āđˆāļ­āļ™āļēāļ—āļĩ (āđ€āļŠāđˆāļ™ āļāļēāļĢāļ„āđ‰āļ™āļŦāļēāļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļ•āļąāļ§āļ•āļ™ āļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļš session) āļ„āđˆāļēāđƒāļŠāđ‰āļˆāđˆāļēāļĒāđƒāļ™āļāļēāļĢāđāļ›āļĨāļ™āļĩāđ‰āļˆāļ°āļŠāļ°āļŠāļĄ Compiled queries āļˆāļ°āđāļ„āļŠāļāļēāļĢāđāļ›āļĨāđ„āļ§āđ‰āļ•āļąāđ‰āļ‡āđāļ•āđˆāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āđāļ­āļ›āļžāļĨāļīāđ€āļ„āļŠāļąāļ™

CompiledQueries.cscsharp
public static class UserQueries
{
    // āļ„āļ­āļĄāđ„āļžāļĨāđŒāļ„āļĢāļąāđ‰āļ‡āđ€āļ”āļĩāļĒāļ§ āđƒāļŠāđ‰āļ‹āđ‰āļģāļ—āļļāļāļāļēāļĢāđ€āļĢāļĩāļĒāļ
    public static readonly Func<AppDbContext, string, CancellationToken, Task<UserSession?>>
        GetActiveSession = EF.CompileAsyncQuery(
            (AppDbContext ctx, string token, CancellationToken ct) =>
                ctx.UserSessions
                    .AsNoTracking()
                    .FirstOrDefault(s => s.Token == token && s.ExpiresAt > DateTime.UtcNow));
}

// āļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™āđƒāļ™ middleware
var session = await UserQueries.GetActiveSession(dbContext, bearerToken, ct);

Compiled queries āļ‚āđ‰āļēāļĄāļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļāļēāļĢāđāļĒāļāļ§āļīāđ€āļ„āļĢāļēāļ°āļŦāđŒ expression tree āļ—āļąāđ‰āļ‡āļŦāļĄāļ” āļ„āļ§āļēāļĄāđāļ•āļāļ•āđˆāļēāļ‡āļ‚āļ­āļ‡āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļˆāļ°āļ§āļąāļ”āđ„āļ”āđ‰āđ€āļ‰āļžāļēāļ°āļšāļ™āđ€āļŠāđ‰āļ™āļ—āļēāļ‡āļ„āļ§āļēāļĄāļ–āļĩāđˆāļŠāļđāļ‡ (āļĄāļēāļāļāļ§āđˆāļē 1,000 āļāļēāļĢāđ€āļĢāļĩāļĒāļ/āļ™āļēāļ—āļĩ) āļŠāļģāļŦāļĢāļąāļš endpoint CRUD āļĄāļēāļ•āļĢāļāļēāļ™ āđāļ„āļŠ query āđƒāļ™āļ•āļąāļ§āļ‚āļ­āļ‡ EF Core āļˆāļąāļ”āļāļēāļĢāļāļēāļĢāđƒāļŠāđ‰āļ‹āđ‰āļģāļāļēāļĢāđāļ›āļĨāļ­āļĒāļđāđˆāđāļĨāđ‰āļ§

āļāļēāļĢāđāļ›āļĨ Parameterized Collection āđƒāļ™ EF Core 10

Query āļ—āļĩāđˆāļāļĢāļ­āļ‡āļ•āļēāļĄāļĢāļēāļĒāļāļēāļĢ ID āđ€āļ›āđ‡āļ™āļŦāļ™āļķāđˆāļ‡āđƒāļ™āļĢāļđāļ›āđāļšāļšāļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ”āđƒāļ™āļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨ EF Core 10 āđ€āļ›āļĨāļĩāđˆāļĒāļ™āļāļĨāļĒāļļāļ—āļ˜āđŒāļāļēāļĢāđāļ›āļĨāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āļŠāļģāļŦāļĢāļąāļš parameterized collections āđāļ—āļ™āļ—āļĩāđˆāļˆāļ°āđ€āļ‚āđ‰āļēāļĢāļŦāļąāļŠāļĢāļēāļĒāļāļēāļĢāđ€āļ›āđ‡āļ™ JSON array (EF Core 8-9) āļŦāļĢāļ·āļ­āđāļ—āļĢāļāļ„āđˆāļēāļ„āļ‡āļ—āļĩāđˆāđāļšāļš inline (EF Core 7 āđāļĨāļ°āļāđˆāļ­āļ™āļŦāļ™āđ‰āļē) EF Core 10 āđāļ›āļĨāđāļ•āđˆāļĨāļ°āļ„āđˆāļēāđ€āļ›āđ‡āļ™āļžāļēāļĢāļēāļĄāļīāđ€āļ•āļ­āļĢāđŒ SQL āđāļĒāļāļāļąāļ™

csharp
// āļāđˆāļ­āļ™āļŦāļ™āđ‰āļē (EF Core 8-9): āļžāļēāļĢāļēāļĄāļīāđ€āļ•āļ­āļĢāđŒ JSON array
// @__ids_0='[1,2,3]'
// SELECT ... WHERE Id IN (SELECT value FROM OPENJSON(@__ids_0))

// EF Core 10: āļžāļēāļĢāļēāļĄāļīāđ€āļ•āļ­āļĢāđŒāđāļĒāļāļāļąāļ™āļžāļĢāđ‰āļ­āļĄ padding
// SELECT ... WHERE Id IN (@ids1, @ids2, @ids3)

var orderIds = new[] { 101, 205, 389 };
var orders = await _context.Orders
    .Where(o => orderIds.Contains(o.Id))
    .ToListAsync(ct);

āļ§āļīāļ˜āļĩāļāļēāļĢāđƒāļŦāļĄāđˆāļ™āļĩāđ‰āđƒāļŦāđ‰āļ‚āđ‰āļ­āļĄāļđāļĨ cardinality āđāļāđˆ query planner āļ‚āļ­āļ‡āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨ āđƒāļ™āļ‚āļ“āļ°āļ—āļĩāđˆāļĒāļąāļ‡āļ„āļ‡āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāļšāļ§āļĄāļ‚āļ­āļ‡ plan cache āļœāđˆāļēāļ™ parameter padding āļŠāļģāļŦāļĢāļąāļšāļāļĢāļ“āļĩāļ—āļĩāđˆāļ§āļīāļ˜āļĩ JSON āļ—āļģāļ‡āļēāļ™āđ„āļ”āđ‰āļ”āļĩāļāļ§āđˆāļē (āļ„āļ­āļĨāđ€āļĨāļāļŠāļąāļ™āļ‚āļ™āļēāļ”āđƒāļŦāļāđˆāļĄāļēāļ) āđƒāļŦāđ‰ override āļžāļĪāļ•āļīāļāļĢāļĢāļĄāļ•āđˆāļ­ query:

csharp
var orders = await _context.Orders
    .Where(o => EF.Parameter(orderIds).Contains(o.Id))  // āļšāļąāļ‡āļ„āļąāļšāđ‚āļŦāļĄāļ” JSON
    .ToListAsync(ct);

āđ€āļĢāļīāđˆāļĄāļāļķāļāļ‹āđ‰āļ­āļĄāđ€āļĨāļĒ!

āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļĢāļđāđ‰āļ‚āļ­āļ‡āļ„āļļāļ“āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āļŠāļĢāļļāļ›

  • āđƒāļŠāđ‰ AsNoTracking() āđāļĨāļ°āļāļēāļĢāļ‰āļēāļĒāļ‚āđ‰āļ­āļĄāļđāļĨāļ”āđ‰āļ§āļĒ Select āđƒāļ™āļ—āļļāļ query āđāļšāļšāļ­āđˆāļēāļ™āļ­āļĒāđˆāļēāļ‡āđ€āļ”āļĩāļĒāļ§āđ€āļžāļ·āđˆāļ­āļ‚āļˆāļąāļ”āļ„āđˆāļēāđƒāļŠāđ‰āļˆāđˆāļēāļĒāļ‚āļ­āļ‡ change tracker
  • āđƒāļŠāđ‰ AsSplitQuery() āđ€āļĄāļ·āđˆāļ­āđ‚āļŦāļĨāļ” collection navigation āļŦāļĨāļēāļĒāļ•āļąāļ§āđ€āļžāļ·āđˆāļ­āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāļĢāļ°āđ€āļšāļīāļ”āđāļšāļš Cartesian
  • āđāļ—āļ™āļ—āļĩāđˆāļĢāļđāļ›āđāļšāļš tracked load-modify-save āļ”āđ‰āļ§āļĒ ExecuteUpdateAsync āđāļĨāļ° ExecuteDeleteAsync āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāļˆāļģāļ™āļ§āļ™āļĄāļēāļ
  • āļ™āļģāļ•āļąāļ§āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ LeftJoin āļˆāļēāļ EF Core 10 āļĄāļēāđƒāļŠāđ‰āđāļ—āļ™āļŦāđˆāļ§āļ‡āđ‚āļ‹āđˆ GroupJoin/SelectMany/DefaultIfEmpty āļ—āļĩāđˆāļĒāļēāļ§āđ€āļŦāļĒāļĩāļĒāļ”
  • āļāļģāļŦāļ™āļ”āļ„āđˆāļē named query filters āđ€āļžāļ·āđˆāļ­āļˆāļąāļ”āļāļēāļĢ soft-delete āđāļĨāļ° multi-tenancy āļ­āļĒāđˆāļēāļ‡āļ­āļīāļŠāļĢāļ°
  • āļ•āļąāđ‰āļ‡āļ„āđˆāļē EnableRetryOnFailure āđāļĨāļ°āļ›āļĢāļąāļšāļ‚āļ™āļēāļ” connection pool āļŠāļģāļŦāļĢāļąāļšāļ„āļ§āļēāļĄāļĒāļ·āļ”āļŦāļĒāļļāđˆāļ™āđƒāļ™ production
  • āļāļģāļŦāļ™āļ” index āđāļšāļšāļœāļŠāļĄāđāļĨāļ°āđāļšāļšāļĄāļĩāļ•āļąāļ§āļāļĢāļ­āļ‡āļ•āļēāļĄāļĢāļđāļ›āđāļšāļš query āļˆāļĢāļīāļ‡ āđ„āļĄāđˆāđƒāļŠāđˆāļāļēāļĢāļ„āļēāļ”āđ€āļ”āļē
  • āļŠāļ‡āļ§āļ™ compiled queries āļŠāļģāļŦāļĢāļąāļšāđ€āļŠāđ‰āļ™āļ—āļēāļ‡āļ—āļĩāđˆāļĢāđ‰āļ­āļ™āļˆāļĢāļīāļ‡āđ† āļ—āļĩāđˆāđ€āļāļīāļ™ 1,000 āļ„āļĢāļąāđ‰āļ‡āļ•āđˆāļ­āļ™āļēāļ—āļĩ
  • āļ›āļĨāđˆāļ­āļĒāđƒāļŦāđ‰ EF Core 10 āļˆāļąāļ”āļāļēāļĢāļāļēāļĢāđāļ›āļĨ parameterized collection āļ•āļēāļĄāļ„āđˆāļēāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™ āđāļĨāļ° override āđ€āļ‰āļžāļēāļ°āđ€āļĄāļ·āđˆāļ­ benchmark āļžāļīāļŠāļđāļˆāļ™āđŒāļ§āđˆāļēāļˆāļģāđ€āļ›āđ‡āļ™

āļ­āđˆāļēāļ™āđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄ: āđ‚āļĄāļ”āļđāļĨ EF Core Advanced āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāļĢāļđāļ›āđāļšāļšāđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āđƒāļ™āļšāļĢāļīāļšāļ—āļ‚āļ­āļ‡āļāļēāļĢāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ āđāļĨāļ° āļ„āļđāđˆāļĄāļ·āļ­ Clean Architecture āļāļąāļš .NET āļŠāļēāļ˜āļīāļ•āļ§āļīāļ˜āļĩāļāļēāļĢāļˆāļąāļ”āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āļŠāļąāđ‰āļ™ repository āđāļĨāļ° service āļ—āļĩāđˆāļŦāđˆāļ­āļŦāļļāđ‰āļĄ query āđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰

āđ€āļĢāļīāđˆāļĄāļāļķāļāļ‹āđ‰āļ­āļĄāđ€āļĨāļĒ!

āļ—āļ”āļŠāļ­āļšāļ„āļ§āļēāļĄāļĢāļđāđ‰āļ‚āļ­āļ‡āļ„āļļāļ“āļ”āđ‰āļ§āļĒāļ•āļąāļ§āļˆāļģāļĨāļ­āļ‡āļŠāļąāļĄāļ āļēāļĐāļ“āđŒāđāļĨāļ°āđāļšāļšāļ—āļ”āļŠāļ­āļšāđ€āļ—āļ„āļ™āļīāļ„āļ„āļĢāļąāļš

āđāļ—āđ‡āļ

#dotnet
#entity-framework
#performance
#best-practices

āđāļŠāļĢāđŒ

āļšāļ—āļ„āļ§āļēāļĄāļ—āļĩāđˆāđ€āļāļĩāđˆāļĒāļ§āļ‚āđ‰āļ­āļ‡

āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ C# āđāļĨāļ° .NET - āļ„āļđāđˆāļĄāļ·āļ­āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒ

āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ C# āđāļĨāļ° .NET: āļ„āļđāđˆāļĄāļ·āļ­āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒ 2026

āļ„āļģāļ–āļēāļĄāļŠāļąāļĄāļ āļēāļĐāļ“āđŒ C# āđāļĨāļ° .NET āļ—āļĩāđˆāļžāļšāļšāđˆāļ­āļĒāļ—āļĩāđˆāļŠāļļāļ” 17 āļ‚āđ‰āļ­ LINQ, async/await, dependency injection, Entity Framework āđāļĨāļ° best practice āļžāļĢāđ‰āļ­āļĄāļ„āļģāļ•āļ­āļšāļĨāļ°āđ€āļ­āļĩāļĒāļ”āđāļĨāļ°āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡āđ‚āļ„āđ‰āļ”

āļ„āļđāđˆāļĄāļ·āļ­āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡ REST API āļ”āđ‰āļ§āļĒ .NET 8 āđāļĨāļ° ASP.NET Core

.NET 8: āļŠāļĢāđ‰āļēāļ‡ API āļ”āđ‰āļ§āļĒ ASP.NET Core

āļ„āļđāđˆāļĄāļ·āļ­āļ‰āļšāļąāļšāļŠāļĄāļšāļđāļĢāļ“āđŒāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāļĢāđ‰āļēāļ‡ REST API āļĢāļ°āļ”āļąāļšāļĄāļ·āļ­āļ­āļēāļŠāļĩāļžāļ”āđ‰āļ§āļĒ .NET 8 āđāļĨāļ° ASP.NET Core āļ„āļĢāļ­āļšāļ„āļĨāļļāļĄ Controller, Entity Framework Core, āļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļ‚āđ‰āļ­āļĄāļđāļĨ āđāļĨāļ°āđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”

āļ„āļđāđˆāļĄāļ·āļ­ Rust āļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļēāļ—āļĩāđˆāļĄāļĩāļ›āļĢāļ°āļŠāļšāļāļēāļĢāļ“āđŒ

Rust: āļžāļ·āđ‰āļ™āļāļēāļ™āļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļēāļ—āļĩāđˆāļĄāļĩāļ›āļĢāļ°āļŠāļšāļāļēāļĢāļ“āđŒāđƒāļ™āļ›āļĩ 2026

āđ€āļĢāļĩāļĒāļ™āļĢāļđāđ‰ Rust āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āļĢāļ§āļ”āđ€āļĢāđ‡āļ§āđ‚āļ”āļĒāļ­āļēāļĻāļąāļĒāļ„āļ§āļēāļĄāļĢāļđāđ‰āļ”āđ‰āļēāļ™āļāļēāļĢāđ€āļ‚āļĩāļĒāļ™āđ‚āļ›āļĢāđāļāļĢāļĄāļ—āļĩāđˆāļĄāļĩāļ­āļĒāļđāđˆ Ownership, borrowing, lifetimes āđāļĨāļ° pattern āļ—āļĩāđˆāļˆāļģāđ€āļ›āđ‡āļ™āļ­āļ˜āļīāļšāļēāļĒāđ„āļ§āđ‰āļŠāļģāļŦāļĢāļąāļšāļ™āļąāļāļžāļąāļ’āļ™āļēāļ—āļĩāđˆāļĄāļēāļˆāļēāļ C++, Java āļŦāļĢāļ·āļ­ Python