Back to "डाटा पहुँच : ओ फंक्शन्स तथा नक्शािंग पथ की तुलना करना ( पार्ट 1 - एंटिटीर कोर)"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

.NET Database EF Core Performance PostgreSQL

डाटा पहुँच : ओ फंक्शन्स तथा नक्शािंग पथ की तुलना करना ( पार्ट 1 - एंटिटीर कोर)

Wednesday, 03 December 2025

जब इमारत का निर्माण किया जाता है, तो सबसे महत्वपूर्ण निर्णय आप बनाने के लिए कैसे डेटा पहुँच और वस्तु निर्मित करने के लिए है।

इस विस्तृत दो भाग निर्देशों में, हम सबसे लोकप्रिय डाटा पहुँच पैटर्न का पता लगाने के लिए जा रहे हैं। हम हमारे उदाहरणों में Npegagsl का उपयोग करते हैं (क्योंकि यह ब्लॉग क्या है कि इस ब्लॉग की शक्ति है), विचारों, मॉडलों, मॉडलों, और व्यापार समाप्तों में बराबर लागू होता है।

पार्ट 1 (यह लेख) एंटिटी फ्रेमवर्क कोर, एसक्यूएल पीढ़ी, तथा सामान्य फन्दों पर ध्यान केंद्रित करता है. पार्ट 2 डी- हॉर, रॉडॉर, रॉटर, वस्तु लाइब्रेरी, और Edss के निकट आ जाएगा.

संबंधित आलेख

यदि आप व्यावहारिक ईएफ कोर कार्यान्वयन में रुचि रखते हैं, मेरे अन्य आलेखों की जाँच करें:

विषय - सूची

डाटा पहुँच की पहेली

.NERT डाटा एक्सेस पार्क को एक स्पेक्ट्रम के रूप में कल्पना की जा सकती है:

Full Abstraction                                      Full Control
     ↓                                                      ↓
[EF Core] → [EF Core Raw SQL] → [Dapper] → [Npgsql ADO.NET]

जैसा कि आप बाएँ से दाएँ ले जाते हैं, आप प्रदर्शन और नियंत्रण प्राप्त करते हैं, लेकिन सुविधा और स्वचालित विशेषताएँ खो देते हैं. चलो विवरण में प्रत्येक तरीका की जाँच करें.

डाटा पहुँच की तुलना

यहाँ एक दृश्य तुलना है कि कैसे हर एक आम प्रश्न संभालता है:

graph TB
    subgraph "EF Core Flow"
        A1[LINQ Query] -->|Compile| B1[Expression Tree]
        B1 -->|Translate| C1[SQL Query]
        C1 -->|Execute| D1[PostgreSQL]
        D1 -->|Results| E1[DbDataReader]
        E1 -->|Materialize| F1[Tracked Entities]
        F1 -->|Return| G1[Application]
    end

    subgraph "Dapper Flow"
        A2[SQL String] -->|Parameterize| B2[DbCommand]
        B2 -->|Execute| C2[PostgreSQL]
        C2 -->|Results| D2[DbDataReader]
        D2 -->|Map| E2[POCOs]
        E2 -->|Return| F2[Application]
    end

    subgraph "Raw Npgsql Flow"
        A3[SQL + Parameters] -->|Build Command| B3[NpgsqlCommand]
        B3 -->|Execute| C3[PostgreSQL]
        C3 -->|Results| D3[NpgsqlDataReader]
        D3 -->|Manual Mapping| E3[Objects]
        E3 -->|Return| F3[Application]
    end

    style A1 stroke:#2563eb,stroke-width:2px
    style B1 stroke:#2563eb,stroke-width:2px
    style C1 stroke:#2563eb,stroke-width:2px
    style D1 stroke:#2563eb,stroke-width:2px
    style E1 stroke:#2563eb,stroke-width:2px
    style F1 stroke:#2563eb,stroke-width:2px
    style G1 stroke:#2563eb,stroke-width:2px

    style A2 stroke:#059669,stroke-width:2px
    style B2 stroke:#059669,stroke-width:2px
    style C2 stroke:#059669,stroke-width:2px
    style D2 stroke:#059669,stroke-width:2px
    style E2 stroke:#059669,stroke-width:2px
    style F2 stroke:#059669,stroke-width:2px

    style A3 stroke:#dc2626,stroke-width:2px
    style B3 stroke:#dc2626,stroke-width:2px
    style C3 stroke:#dc2626,stroke-width:2px
    style D3 stroke:#dc2626,stroke-width:2px
    style E3 stroke:#dc2626,stroke-width:2px
    style F3 stroke:#dc2626,stroke-width:2px

परफ़ॉर्मेंस वी डेवलपर उत्पाद विश्लेषण

graph LR
    A[High Productivity<br/>Low Performance] --> B[EF Core<br/>Full Tracking]
    B --> C[EF Core<br/>No Tracking]
    C --> D[EF Core<br/>Raw SQL]
    D --> E[Dapper]
    E --> F[Raw Npgsql]
    F --> G[Low Productivity<br/>High Performance]

    style A stroke:#2563eb,stroke-width:2px
    style B stroke:#2563eb,stroke-width:2px
    style C stroke:#3b82f6,stroke-width:2px
    style D stroke:#059669,stroke-width:2px
    style E stroke:#059669,stroke-width:2px
    style F stroke:#dc2626,stroke-width:2px
    style G stroke:#dc2626,stroke-width:2px

एंटिटी फ्रेमवर्क कोर: पूरा- विवरण!

एंटिटी फ्रेमवर्क कोर माइक्रोसॉफ़्ट फ्लेग ओ गिरोह है, आपके डाटाबेस के ऊपर एक पूर्ण शटमा प्रदान करता है. यह एसक्यूएल को समर्थन करता है Npegl. secrummramr. प्रेषित प्रदाता.

आपकी परियोजना में ईएफ को बनाने के लिए व्यावहारिक मार्गदर्शन के लिए, मेरे लेख को देखिए ब्लॉग पोस्ट के लिए एंटिटी फ्रेमवर्क जोड़े.

कुंजी फीचर

  • ट्रैकिंग बदलें: ट्रैक्स एंटिटी परिवर्तन स्वचालित करें तथा उपयुक्त एसक्यूएल तैयार करता है
  • उत्प्रवासन: कोड- प्रथम स्कीमा प्रबंधन तथा संस्करण नियंत्रण (देखें) EF उत्प्रवासन सही दिशा दिखाता है)
  • एलएसईएस प्रदाताC# भाषा बनाने के लिए टाइप डिरेक्ट्री
  • ला zy/Eren लोड किया जा रहा है: संबंधित एंटिटी के लिए उपयुक्त अधिभारण की नीति
  • विस्तृत एसक्यूएल विशेषताएँ: पूर्ण पाठ खोज (e)इस अंक में ये लेख भी हैं, JSON स्तम्भ, ऐरे, सीमा प्रकार
  • इंटरफेस और घटनाएँ: पार करने की चिंताओं के लिए संरक्षा बिन्दु

उदाहरण: ईएफ कोर के साथ मूल अपराध

public class BlogDbContext : DbContext
{
    public DbSet<BlogPost> BlogPosts { get; set; }
    public DbSet<Comment> Comments { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseNpgsql("Host=localhost;Database=blog;Username=postgres;Password=secret");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // PostgreSQL-specific: Full-text search
        modelBuilder.Entity<BlogPost>()
            .HasGeneratedTsVectorColumn(
                p => p.SearchVector,
                "english",
                p => new { p.Title, p.Content })
            .HasIndex(p => p.SearchVector)
            .HasMethod("GIN");

        // PostgreSQL array type
        modelBuilder.Entity<BlogPost>()
            .Property(p => p.Tags)
            .HasPostgresArrayConversion(
                tag => tag.ToLowerInvariant(),
                tag => tag);
    }
}

public class BlogPost
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public string[] Tags { get; set; }
    public NpgsqlTsVector SearchVector { get; set; }
    public List<Comment> Comments { get; set; }
    public DateTime PublishedDate { get; set; }
}

// Usage
public class BlogService
{
    private readonly BlogDbContext _context;

    public async Task<List<BlogPost>> GetRecentPostsAsync(int count)
    {
        return await _context.BlogPosts
            .Include(p => p.Comments)
            .OrderByDescending(p => p.PublishedDate)
            .Take(count)
            .ToListAsync();
    }

    public async Task<List<BlogPost>> SearchPostsAsync(string searchTerm)
    {
        return await _context.BlogPosts
            .Where(p => p.SearchVector.Matches(EF.Functions.ToTsQuery("english", searchTerm)))
            .ToListAsync();
    }

    public async Task AddPostAsync(BlogPost post)
    {
        _context.BlogPosts.Add(post);
        await _context.SaveChangesAsync();
    }
}

एसक्यूएल के साथ ईएफ कोर

EF कोरल रॉ एसक्यूएल जांच को भी समर्थन देता है जब आपको अधिक नियंत्रण की आवश्यकता होती है:

public async Task<List<BlogPost>> GetPostsByComplexCriteriaAsync()
{
    var searchTerm = "postgresql";

    return await _context.BlogPosts
        .FromSqlInterpolated($@"
            SELECT * FROM ""BlogPosts""
            WHERE ""SearchVector"" @@ to_tsquery('english', {searchTerm})
            AND array_length(""Tags"", 1) > 3
            ORDER BY ts_rank(""SearchVector"", to_tsquery('english', {searchTerm})) DESC
        ")
        .ToListAsync();
}

// Or with DbDataReader for maximum control
public async Task<List<PostStatistics>> GetPostStatisticsAsync()
{
    using var command = _context.Database.GetDbConnection().CreateCommand();
    command.CommandText = @"
        SELECT
            DATE_TRUNC('month', ""PublishedDate"") as Month,
            COUNT(*) as PostCount,
            AVG(ARRAY_LENGTH(""Tags"", 1)) as AvgTags
        FROM ""BlogPosts""
        GROUP BY DATE_TRUNC('month', ""PublishedDate"")
        ORDER BY Month DESC";

    await _context.Database.OpenConnectionAsync();

    var results = new List<PostStatistics>();
    using var reader = await command.ExecuteReaderAsync();

    while (await reader.ReadAsync())
    {
        results.Add(new PostStatistics
        {
            Month = reader.GetDateTime(0),
            PostCount = reader.GetInt32(1),
            AverageTags = reader.GetDouble(2)
        });
    }

    return results;
}

EF कोर प्रयोग करने के लिए जब

डाउनलोड किया जा रहा है

  • स्कीमा माँगों के साथ नया अनुप्रयोग बनाना
  • आपको मजबूत टाइपिंग तथा कंपाइल- समय क्वेरी की आवश्यकता है
  • उत्प्रवासन तथा प्रसंग संस्करण महत्वपूर्ण हैं (देखें) मेरी उत्प्रवासन)
  • आपका टीम एसक्यूएल पर वस्तुओं के साथ काम करना पसंद करता है
  • आप संबंधों के साथ जटिल डोमेन मॉडलों का उपयोग कर रहे हैं
  • विकास गति रॉ प्रदर्शन से ज्यादा कठिन है
  • आपको पार- डाटा पोर्ट उपयोगिता की आवश्यकता है (हालांकि- विशिष्ट विशेषताएँ जो आप में हैं)

❍ जब आप किसी को ठोकर खाते हैं, तो उसे माफ मत कीजिए:

  • अधिकतम प्रदर्शन गंभीर है (उच्च श्रेणी के माध्यम से एपीआई, बैच प्रक्रिया)
  • आपके पास जटिल, हाथ-कोल्ड एसक्यूएल जांच है
  • तुम्हारी खोज वस्तु ग्राफ के लिए अच्छी तरह से नक्शा नहीं है
  • आप प्रत्येक एसक्यूएल कथन पर ठीक- अक्षम नियंत्रण की आवश्यकता है
  • स्मृति प्रयोग एक महत्वपूर्ण प्रतिरोध है (ऊपर ट्रैक करना बदला जा रहा है)
  • आप विरासत प्रसंगों के साथ काम कर रहे हैं जो अधिवेशनों के लिए नक्शा नहीं है

ईएफ कोर एसक्यूएल पीढ़ी: समझ में क्या होता है

EF कोर का उपयोग करने के सबसे महत्वपूर्ण पहलुओं में से एक समझ है क्या एसक्यूएल यह उत्पन्न करता है. EF कोर कोर ने सालों के दौरान उल्लेखनीय सुधार किया है, लेकिन यह महत्वपूर्ण है कि CATCT को भेजा जा रहा है.

उत्पन्न किए गए एसक्यूएल को देखना

// Enable sensitive data logging and detailed errors (development only!)
optionsBuilder
    .UseNpgsql(connectionString)
    .EnableSensitiveDataLogging()
    .EnableDetailedErrors()
    .LogTo(Console.WriteLine, LogLevel.Information);

// Or use logging to see SQL
public class BlogService
{
    private readonly BlogDbContext _context;
    private readonly ILogger<BlogService> _logger;

    public async Task<List<BlogPost>> GetPostsAsync()
    {
        var query = _context.BlogPosts
            .Where(p => p.PublishedDate > DateTime.UtcNow.AddDays(-30))
            .OrderByDescending(p => p.PublishedDate);

        // View the SQL before execution
        var sql = query.ToQueryString();
        _logger.LogInformation("Executing query: {Sql}", sql);

        return await query.ToListAsync();
    }
}

उदाहरण: सरल क्वेरी

C# LONQ:

var recentPosts = await _context.BlogPosts
    .Where(p => p.CategoryId == 5)
    .OrderByDescending(p => p.PublishedDate)
    .Take(10)
    .ToListAsync();

एसक्यूएल उत्पन्न करें (y)ईएफ कोर 8+):

SELECT b."Id", b."Title", b."Content", b."CategoryId", b."PublishedDate"
FROM "BlogPosts" AS b
WHERE b."CategoryId" = @__categoryId_0
ORDER BY b."PublishedDate" DESC
LIMIT @__p_1

ध्यान दें कि ईएफ कोर 8+ शुद्ध बनाता है, कुशल एसक्यूएल को सही पैरामीटर के साथ साफ करता है. ईएफ कोर १० यह प्रवृत्ति और भी अधिक सुधार के साथ जारी है ।

उदाहरण: शामिल हों (एफएफ से पहले)

C# कोड:

var posts = await _context.BlogPosts
    .Include(p => p.Category)
    .Include(p => p.Comments)
    .ToListAsync();

पुराना एसक्यूएल (ईएफ कोर 3. 11 - कार्टियन विस्फोट):

SELECT b."Id", b."Title", c."Id", c."Name", cm."Id", cm."Content"
FROM "BlogPosts" AS b
LEFT JOIN "Categories" AS c ON b."CategoryId" = c."Id"
LEFT JOIN "Comments" AS cm ON b."Id" = cm."BlogPostId"
ORDER BY b."Id", c."Id"

जिसने (हर चीज़ को) पैदा किया कार्टेसियन उत्पाद - अगर एक पोस्ट में 10 टिप्पणी हैं, कि पंक्ति 10 बार दोहराया जाता है!

उदाहरण: अलग- अलग कतार (ईएफ कोर 5+)

क्वैरी के साथ C# कोड:

var posts = await _context.BlogPosts
    .Include(p => p.Category)
    .Include(p => p.Comments)
    .AsSplitQuery()  // ← This is the key!
    .ToListAsync();

एसक्यूएल तैयार करें (M)

-- Query 1: Get posts and categories
SELECT b."Id", b."Title", b."Content", c."Id", c."Name"
FROM "BlogPosts" AS b
LEFT JOIN "Categories" AS c ON b."CategoryId" = c."Id"

-- Query 2: Get comments for those posts
SELECT cm."Id", cm."Content", cm."BlogPostId"
FROM "Comments" AS cm
INNER JOIN (
    SELECT b."Id"
    FROM "BlogPosts" AS b
) AS t ON cm."BlogPostId" = t."Id"
ORDER BY t."Id"

यह कार्टियन उत्पाद को खत्म करता है और अकसर होता है अधिक तेजी से संग्रह के लिए!

उदाहरण: फिल्टर्ड शामिल (एफ़ कोर ५+)

C# कोड:

var posts = await _context.BlogPosts
    .Include(p => p.Comments.Where(c => c.IsApproved))
    .ToListAsync();

एसक्यूएल बनाएँ:

SELECT b."Id", b."Title", b."Content", t."Id", t."Content", t."IsApproved"
FROM "BlogPosts" AS b
LEFT JOIN (
    SELECT c."Id", c."Content", c."IsApproved", c."BlogPostId"
    FROM "Comments" AS c
    WHERE c."IsApproved" = TRUE
) AS t ON b."Id" = t."BlogPostId"
ORDER BY b."Id"

उदाहरण: JSON स्तम्भ क्वार्टर (EF कोर 7+)

C# कोड:

public class BlogPost
{
    public int Id { get; set; }
    public string Title { get; set; }
    public PostMetadata Metadata { get; set; }  // Stored as JSONB
}

public class PostMetadata
{
    public bool IsFeatured { get; set; }
    public int ViewCount { get; set; }
    public List<string> RelatedTags { get; set; }
}

// Query JSON properties
var featuredPosts = await _context.BlogPosts
    .Where(p => p.Metadata.IsFeatured)
    .ToListAsync();

एसक्यूएल बनाएँ:

SELECT b."Id", b."Title", b."Metadata"
FROM "BlogPosts" AS b
WHERE b."Metadata" ->> 'IsFeatured' = 'true'

EF कोर 7+ JSON संपत्ति का अनुवाद JSON ऑपरेटरों में कर सकता है!

उदाहरण: बल्क अद्यतन (E)

पुराना मार्ग (प्रयोगात्मक):

var posts = await _context.BlogPosts
    .Where(p => p.CategoryId == 5)
    .ToListAsync();

foreach (var post in posts)
{
    post.IsArchived = true;
}

await _context.SaveChangesAsync();  // Generates N UPDATE statements!

नया मार्ग (ईएफओ कोर 7+):

await _context.BlogPosts
    .Where(p => p.CategoryId == 5)
    .ExecuteUpdateAsync(setters => setters
        .SetProperty(p => p.IsArchived, true));

डी- एसक्यूएल तैयार करें (केवल क्वैरी!):

UPDATE "BlogPosts" AS b
SET "IsArchived" = TRUE
WHERE b."CategoryId" = 5

यह एक है विशाल सुधार - एन के बजाय एक एसक्यूएल कथन!

उदाहरण: बल्क मिटाएँ (ईएफ कोर 7+)

पुराना:

var oldPosts = await _context.BlogPosts
    .Where(p => p.PublishedDate < DateTime.UtcNow.AddYears(-5))
    .ToListAsync();

_context.BlogPosts.RemoveRange(oldPosts);
await _context.SaveChangesAsync();  // N DELETE statements

नया मार्ग:

await _context.BlogPosts
    .Where(p => p.PublishedDate < DateTime.UtcNow.AddYears(-5))
    .ExecuteDeleteAsync();

एसक्यूएल बनाएँ:

DELETE FROM "BlogPosts" AS b
WHERE b."PublishedDate" < @__p_0

उदाहरण: जटिल सुझाव

C# कोड:

var categoryStats = await _context.Categories
    .Select(c => new CategoryStats
    {
        CategoryName = c.Name,
        PostCount = c.BlogPosts.Count(),
        LatestPostDate = c.BlogPosts.Max(p => p.PublishedDate),
        AverageComments = c.BlogPosts.Average(p => p.Comments.Count)
    })
    .ToListAsync();

एसक्यूएल तैयार करें (ईएफ कोर 8+/ 10):

SELECT c."Name" AS "CategoryName",
       COUNT(*)::int AS "PostCount",
       MAX(b."PublishedDate") AS "LatestPostDate",
       COALESCE(AVG((
           SELECT COUNT(*)::int
           FROM "Comments" AS c0
           WHERE b."Id" = c0."BlogPostId"
       ))::double precision, 0.0) AS "AverageComments"
FROM "Categories" AS c
LEFT JOIN "BlogPosts" AS b ON c."Id" = b."CategoryId"
GROUP BY c."Id", c."Name"

एसक्यूएल पूरा पाठ खोजQuery

पूर्ण पाठ खोज में एक गहरी तेज़ी के लिए, मेरे लेख को देखें ईएफ कोर के साथ पूर्ण पाठ खोज को लागू कर रहा है.

C# कोड:

var searchResults = await _context.BlogPosts
    .Where(p => p.SearchVector.Matches(EF.Functions.ToTsQuery("english", "postgresql & performance")))
    .OrderByDescending(p => p.SearchVector.Rank(EF.Functions.ToTsQuery("english", "postgresql & performance")))
    .Take(20)
    .ToListAsync();

एसक्यूएल बनाएँ:

SELECT b."Id", b."Title", b."Content", b."SearchVector"
FROM "BlogPosts" AS b
WHERE b."SearchVector" @@ to_tsquery('english', @__searchTerm_0)
ORDER BY ts_rank(b."SearchVector", to_tsquery('english', @__searchTerm_0)) DESC
LIMIT 20

कठिन EF कोर चेतावनी तथा पित्फ

1. ट्रेकिंग मेमोरी बदलिए

समस्या:

// ❌ DANGER: This can cause memory leaks!
public class PostCache
{
    private readonly BlogDbContext _context;
    private List<BlogPost> _cachedPosts;

    public PostCache(BlogDbContext context)
    {
        _context = context;
    }

    public async Task LoadCacheAsync()
    {
        // These entities are now tracked by the context
        _cachedPosts = await _context.BlogPosts.ToListAsync();

        // The DbContext holds references to these entities FOREVER
        // They can never be garbage collected while the context lives!
    }
}

क्यों यह एक समस्या है:

  • जीवन भर के लिए ट्रैकन स्मृति में बने रहते हैं DbContext
  • स्थिति बदलने वाले संदर्भों को बनाए रखते हैं, कचरे के संग्रह से
  • लंबे समय के संदर्भ (जैसे, एकलटन्स) = स्मृति रिसाव
  • usNTC, संदर्भ डिफ़ॉल्ट से नियंत्रित होता है
  • लेकिन अगर आप कैश ट्रैक प्रमाणपत्र, आप मुसीबत में हैं

समाधानः

public async Task LoadCacheAsync()
{
    // ✅ Use AsNoTracking() for read-only queries
    _cachedPosts = await _context.BlogPosts
        .AsNoTracking()
        .ToListAsync();

    // Or detach entities after loading
    var posts = await _context.BlogPosts.ToListAsync();
    foreach (var post in posts)
    {
        _context.Entry(post).State = EntityState.Detached;
    }
    _cachedPosts = posts;
}

2. प्रॉक्सी बनाना और लाफी लोड करने के खतरे

खतरे: अगर आप कमज़ोर पड़ गए हैं, तो कम - से - कम गैर - ज़रूरी चीज़ों का इस्तेमाल मत कीजिए

प्रॉक्सी + क कैशिंग = जी.

यदि आप प्रॉक्सी सक्षम हैं, आप डीबी संदर्भ उदाहरण या कैश एंटिटीज़ को कैश करते हैं, आप विल रिसाव मेमोरी. प्रॉक्सी यांत्रिकी डीबी संदर्भ को संदर्भ बनाए रखती है, कचरे के संग्रह को रोक रही है. यह ईएफ कोर अनुप्रयोगों में सबसे आम और खतरनाक ग़लत ग़लतियों में से एक है.

लघुछवियों का नियम: हमेशा संग्रह को साफ - सफाई के साथ शामिल कीजिए .Include()सिर्फ प्रॉक्सी का उपयोग करें यदि आप पूरी तरह से जानते हैं और कभी नहीं, हमेशा कैश प्रॉक्सी एंटिटी.

समस्या 1: N+1 प्रश्न दुःस्वप्न

// ❌ Enable lazy loading
optionsBuilder
    .UseNpgsql(connectionString)
    .UseLazyLoadingProxies();  // Convenient but dangerous!

public class BlogPost
{
    public int Id { get; set; }
    public string Title { get; set; }
    public virtual Category Category { get; set; }  // Virtual = proxy
    public virtual List<Comment> Comments { get; set; }
}

// Somewhere in your code
var posts = await _context.BlogPosts.ToListAsync();

foreach (var post in posts)
{
    Console.WriteLine(post.Category.Name);  // N+1 query here!
    Console.WriteLine(post.Comments.Count);  // Another N+1 query!
}

क्या होता है:

  1. प्रथम क्वैरी सभी पोस्टों को लोड किया जा रहा है
  2. के लिए प्रत्येक पोस्ट, एक्सेसिंग Category डाटाबेस क्वैरी ट्रिगर करता है
  3. के लिए प्रत्येक पोस्ट, एक्सेसिंग Comments अन्य क्वैरी ट्रिगर करता है
  4. यदि आपके पास 100 पोस्ट हैं, तो आपने अभी चलाया 201 फ्लू!

समस्या 2: प्रॉक्सी + कलिंग = मेमोरी लीक

// ❌ CATASTROPHIC: Lazy loading proxies + caching
public class BlogPostCache
{
    private static List<BlogPost> _cachedPosts;
    private readonly BlogDbContext _context;

    public BlogPostCache()
    {
        var optionsBuilder = new DbContextOptionsBuilder<BlogDbContext>();
        optionsBuilder
            .UseNpgsql(connectionString)
            .UseLazyLoadingProxies();  // ⚠️ DANGER!

        _context = new BlogDbContext(optionsBuilder.Options);
    }

    public async Task<List<BlogPost>> GetCachedPostsAsync()
    {
        if (_cachedPosts == null)
        {
            // ❌ These proxy entities hold references to _context
            _cachedPosts = await _context.BlogPosts.ToListAsync();
        }
        return _cachedPosts;
    }
}

क्यों यह विनाशकारी है:

  • प्रॉक्सी निगम उनके लिए एक संदर्भ रखते हैं DbContext
  • वह DbContext सभी निश्चित निगमों का संदर्भ बनाए रखता है
  • आपका कैश अब पूरी वस्तु ग्राफ को कूड़ेदान होने से रोकता है
  • हर बार जब आप एक नेविगेशन गुण की पहुँच करते हैं, तो यह ट्रिगर हो सकता है इस्तेमाल किया जा रहा है पुराना, कैश्ड संदर्भ
  • मेमोरी बढ़ती जाती है जब आप ज्यादा डाटा लोड करते हैं
  • आप अंत में याद या निकास कनेक्शन पूल से बाहर निकलना होगा

हल: समझदारी से काम लीजिए

// ✅ NEVER use lazy loading proxies - always be explicit
optionsBuilder
    .UseNpgsql(connectionString);
    // NO .UseLazyLoadingProxies()!

public class BlogPost
{
    public int Id { get; set; }
    public string Title { get; set; }
    public Category Category { get; set; }  // NOT virtual
    public List<Comment> Comments { get; set; }  // NOT virtual
}

// ✅ Explicit eager loading - you control what's loaded
var posts = await _context.BlogPosts
    .Include(p => p.Category)
    .Include(p => p.Comments)
    .ToListAsync();

// ✅ Or use split queries for better performance
var posts = await _context.BlogPosts
    .Include(p => p.Category)
    .Include(p => p.Comments)
    .AsSplitQuery()
    .ToListAsync();

// ✅ Or use projection to DTOs (best for caching)
var posts = await _context.BlogPosts
    .Select(p => new PostDto
    {
        Title = p.Title,
        CategoryName = p.Category.Name,
        CommentCount = p.Comments.Count
    })
    .ToListAsync();

// ✅ If you MUST cache, use AsNoTracking and no proxies
public class SafeBlogPostCache
{
    private static List<BlogPost> _cachedPosts;
    private readonly IDbContextFactory<BlogDbContext> _contextFactory;

    public async Task<List<BlogPost>> GetCachedPostsAsync()
    {
        if (_cachedPosts == null)
        {
            using var context = await _contextFactory.CreateDbContextAsync();

            _cachedPosts = await context.BlogPosts
                .Include(p => p.Category)
                .Include(p => p.Comments)
                .AsNoTracking()  // Critical for caching!
                .ToListAsync();
        }
        return _cachedPosts;
    }
}

जब बीमारियाँ स्वीकार्य हो सकती हैं (संत्र बंद हो जाता है):

प्रॉक्सी लोड करने पर सिर्फ तभी स्वीकार्य हो सकता है:

  1. +/- आपके पास है छोटा जीवन स्कोप्ड संदर्भ (उदा. g, प्रति एचटीटीपी निवेदन)
  2. सैपान आप कभी नहीं कैश एंटिटी
  3. D+1 क्वैरी प्रदर्शन के साथ आप ठीक हैं
  4. आप कल्पना कर रहे हैं और बाद में विकृत हो जाएगा
  5. अपनी टीम को इन बातों को अच्छी तरह समझने की कोशिश कीजिए

लेकिन फिर भी, स्पष्ट Include() लगभग हमेशा बेहतर विकल्प है क्योंकि:

  • यह डाटा लोड करता है साफ और साफ - साफ
  • यह है ऑमाइजेशन के लिए आसान (आप देख सकते हैं कि क्या लोड किया जा रहा है)
  • यह दुर्घटनात्मक N+1 जांच को रोकता है
  • यह कैशिंग तथा लंबी आयु के संदर्भों के साथ सही काम करता है
  • यह है दिशा पास करने की छूट दी गई साक्षी है वे (हवाएँ) जिनकी चोटी छोड़ दी जाती है

3 चर्चा जीवन समय पर की जाती है

उत्पादन में जीवन - अवधि का प्रबंधन करने के बारे में अधिक जानकारी के लिए, मेरे लेख को देखिए EF उत्प्रवासन सही दिशा दिखाता है.

समस्या:

// ❌ NEVER do this - singleton DbContext
public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<BlogDbContext>();  // WRONG!
}

// ❌ Also wrong - storing context in static field
public static class DataAccess
{
    private static BlogDbContext _context = new BlogDbContext();

    public static async Task<BlogPost> GetPostAsync(int id)
    {
        return await _context.BlogPosts.FindAsync(id);
    }
}

क्यों गलत है:

  • DbContext है थ्रेड नहीं निर्मित करें
  • वर्तमान निवेदन डाटा खराब कर देगा
  • ट्रैकर हमेशा के लिए खत्म हो जाता है
  • कनेक्शन पूल बन्द हो गया
  • कैश से स्टेनल डाटा

समाधानः

// ✅ Use scoped lifetime (default in ASP.NET Core)
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<BlogDbContext>(options =>
        options.UseNpgsql(connectionString));
}

// ✅ Or use DbContext factory for background services
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContextFactory<BlogDbContext>(options =>
        options.UseNpgsql(connectionString));
}

public class BlogBackgroundService
{
    private readonly IDbContextFactory<BlogDbContext> _contextFactory;

    public async Task ProcessPostsAsync()
    {
        // Create a new context for this operation
        using var context = await _contextFactory.CreateDbContextAsync();

        var posts = await context.BlogPosts.ToListAsync();
        // Process posts...
    }
}

4. नेविगेशन गुण में शामिल होने की पूर्वनिर्धारितता

समस्या:

public class BlogPost
{
    public int Id { get; set; }
    public string Title { get; set; }
    public List<Comment> Comments { get; set; }
}

// You query one post...
var post = await _context.BlogPosts.FirstAsync();

// Add a new comment
var newComment = new Comment { Content = "Great post!" };
post.Comments.Add(newComment);

await _context.SaveChangesAsync();

// ❌ EF Core saves the comment, BUT...
// If Comments wasn't loaded, you just lost all existing comments!
// The collection is empty, so EF thinks there are no other comments

समाधानः

// ✅ Always load navigation properties before modifying
var post = await _context.BlogPosts
    .Include(p => p.Comments)
    .FirstAsync(p => p.Id == postId);

post.Comments.Add(newComment);
await _context.SaveChangesAsync();

// Or add directly to the DbSet
_context.Comments.Add(new Comment
{
    BlogPostId = postId,
    Content = "Great post!"
});
await _context.SaveChangesAsync();

5 के रूप में वीएस सिंक मिक्सिंग

समस्या:

// ❌ Mixing sync and async - deadlock risk!
public async Task<BlogPost> GetPostAsync(int id)
{
    var post = _context.BlogPosts
        .Where(p => p.Id == id)
        .FirstOrDefault();  // Sync method in async context!

    return post;
}

// ❌ Even worse - blocking async code
public BlogPost GetPost(int id)
{
    return _context.BlogPosts
        .FirstOrDefaultAsync(p => p.Id == id)
        .Result;  // DEADLOCK RISK!
}

समाधानः

// ✅ Use async all the way
public async Task<BlogPost> GetPostAsync(int id)
{
    return await _context.BlogPosts
        .FirstOrDefaultAsync(p => p.Id == id);
}

// ✅ Or use sync all the way (not recommended for ASP.NET Core)
public BlogPost GetPost(int id)
{
    return _context.BlogPosts
        .FirstOrDefault(p => p.Id == id);
}

ईएफ कोर १०: नया और ब्रेकिंग परिवर्तन

के साथ ईएफ कोर १० 10 के साथ रिहा किए गए .NT 10 में बहुत से महत्वपूर्ण परिवर्तन हैं जब अद्यतन किया जा रहा है. पूरे सूची के लिए देखें. ईएफ कोर 10 में बदलावों को तोड़ रहे हैं.

रन समय आवश्यकताएँ

ईएफ कोर 10 की जरूरत है .नेट 10. यह नहीं चला जाएगा .NT 8, eET 9, or eET फ्रेमवर्क. यह सबसे महत्वपूर्ण परिवर्तन है - सुनिश्चित करें कि आपके परियोजना लक्ष्य को साफ करें net10.0 अद्यतन से पहले.

क्वैरी अप ब्रेकिंग परिवर्तन

1. पैरामीटर्ड संग्रह (डिफ़ॉल्ट परिवर्तित)

ईएफ कोर 10 परिवर्तन कैसे करें Contains() एसक्यूएल को उपयोग में लाया जाता है. पहले, ईएफ को प्रयोग में लिया जाता है OpenJson() ( एसक्यूएल सर्वर) या समान. अब यह डिफ़ॉल्ट है. छैतिज पैमाना इससे बेहतर क्वैरी योजना कैशिंग प्रदान होती है.

प्रभाव: आप अन्य एसक्यूएल को भी देख सकते हैं जैसे कि चरनी के लिए बनाया गया:

var ids = new List<int> { 1, 2, 3, 4, 5 };
var posts = await _context.BlogPosts
    .Where(p => ids.Contains(p.Id))
    .ToListAsync();

EF कोर 8/9 (फ़ाइलेन):

SELECT b."Id", b."Title"
FROM "BlogPosts" AS b
WHERE b."Id" IN (SELECT value FROM OPENJSON(@__ids_0))

EF कोर 10 (मीटर ऐरे):

SELECT b."Id", b."Title"
FROM "BlogPosts" AS b
WHERE b."Id" = ANY(@__ids_0)  -- PostgreSQL
-- Or: WHERE b."Id" IN (@__ids_0_0, @__ids_0_1, @__ids_0_2, ...) -- SQL Server

यदि आप अनुभव करते हैं प्रदर्शन रीग्रेसन, पुराने व्यवहार में वापस आता है:

// SQL Server
optionsBuilder.UseSqlServer(connectionString,
    o => o.UseParameterizedCollectionMode(ParameterTranslationMode.Constant));

// PostgreSQL - generally parameter arrays work well, but you can opt out if needed

2 अद्यतन करें

वह ExecuteUpdateAsync हस्ताक्षर ग़ैर- कुशल भेड़ के मेम्ने को समर्थन देने के लिए परिवर्तित किया गया है. यह ज्यादा ढीली है लेकिन यह कुछ भी नहीं करता है. ब्रेक कोड जो एक्सप्रेशन ट्री प्रोज़ेक्टिव रूप से बनाया गया है:

पुराना तरीका (केर कोर 7- 9):

// This still works
await _context.BlogPosts
    .Where(p => p.CategoryId == 5)
    .ExecuteUpdateAsync(setters => setters
        .SetProperty(p => p.IsArchived, true));

नया ईएफ कोर १० - नॉन- स्प्क्शन भेड़ के बच्चे:

// Now you can include custom logic!
await _context.BlogPosts
    .Where(p => p.CategoryId == 5)
    .ExecuteUpdateAsync(setters =>
    {
        setters.SetProperty(p => p.IsArchived, true);
        setters.SetProperty(p => p.UpdatedAt, DateTime.UtcNow);
        // Can now include conditional logic, loops, etc.
    });

3. जटिल क़िस्म स्तम्भ नाम

ईएफ कोर 10 बदल देते हैं कि कैसे जटिल किस्म के स्तम्भ डेटा भ्रष्टाचार को रोकने के लिए रखे जाते हैं:

ईएफ कोर 9:

NestedComplex_Property

ईएफ कोर १०: १

OuterComplex_NestedComplex_Property

उत्प्रवासन प्रभाव: यदि आपके पास विविध क़िस्मों के मौजूदा तालिका हैं, तो आपको स्तम्भों का नाम बदलना या सुस्पष्ट स्तम्भों के नामों को कॉन्फ़िगर करना होगा:

modelBuilder.Entity<Order>()
    .ComplexProperty(o => o.ShippingAddress)
    .Property(a => a.Street)
    .HasColumnName("ShippingAddress_Street"); // Explicit name

एसक्यूएल सर्वर / एसक्यूएल एसक्यूएल विशिष्ट परिवर्तन

JSON डाटा क़िस्म डिफ़ॉल्ट

क्वीप एसक्यूएल डाटाबेस या एसक्यूएल सर्वर के लिए 2025 (प्रयोगात्मक स्तर 170+), EF कोर को नए निवासियों के लिए डिफ़ॉल्ट बनाता है JSON डाटा क़िस्म इसके बजाए NVARCHAR(MAX).

स्तर बनाए रखने के लिए (यदि आपको पीछे की संगतता की आवश्यकता है):

optionsBuilder.UseAzureSql(connectionString,
    o => o.UseCompatibilityLevel(160)); // Use old NVARCHAR behavior

जांचसूची को उन्नत कर रहा है

EF कोर 8/9 से ईएफ को कम करने के दौरान

  1. © अद्यतन लक्ष्य को net10.0
  2. हट्स अद्यतन सभी Microsoft.EntityFrameworkCore.* पैकेज को 10x
  3. चैलेंज अद्यतन Npgsql.EntityFrameworkCore.PostgreSQL 10x में.
  4. दोबारा विचार करने की कोशिश करें Contains() प्रदर्शन परिवर्तनों के लिए संग्रह सहित
  5. तुमने किसी भी कोड को जाँच लिया है जो बहुत ही व्यवस्थित तरीके से काम करता है ExecuteUpdateAsync एक्सप्रेशन
  6. जटिल जाँच के लिए जटिल किस्म के स्तम्भों के नाम जाँचें यदि नेब्ड जटिल किस्म का उपयोग किया हो
  7. वीएनसी एसक्यूएल सर्वर JSON स्तम्भ प्रयोग यदि एसक्यूएल एसक्यूएल/ एसक्यूएल सर्वर का उपयोग करता है 2025

नया ( हाइलाइट) क्या है

  • उन्नत LONQ अनुवाद: जटिल क़ब्रों के लिए बेहतर एसक्यूएल पीढ़ी
  • अद्यतन में नॉनकेन दुडाडाडाज: बड़े - बड़े अद्यतनों में और भी विशेषज्ञ
  • बेहतर पैरामीटर हैंडल करना: क्वैरी प्लानिंग
  • उन्नत JSON समर्थनएसक्यूएल सर्वर 2025 पर नेटिव JSON क़िस्म
  • परफ़ॉर्मेंस सुधार: तेज सामग्री और ट्रैकिंग बदलने के लिए

परफ़ॉर्मेंस कैरेक्टर्स

  • परफार्मेंस क्वैरी करें: 20-50% चोटी की तुलना साधारण इमारतों के लिए Dappsander से की गयी है
  • मेमोरी उपयोगट्रैक और प्रॉक्सी पीढ़ी को बदलने के लिए उच्चतर कारण:
  • प्रथम क्वैरी: धीमा (स्कॉरिफाइड तथा कलिंग)
  • सबस्टेंट क्वाटरक्वैरी कैश को कम्पाइल करने के लिए तेज तेज
  • प्रविष्ट करें/ अद्यतन करें: स्वचलित बदल ट्रैक अप को आगे बढ़ाता है
  • बल्क संचालन: डिफ़ॉल्ट तरीके से खराब प्रदर्शन (प्रेशण) ईएफरे.ब्लिक विस्तार EF कोर 7+ में मिटाएँ या अद्यतन करें

EF कोर के लिए उत्तम अभ्यास

सामान्य मार्गदर्शकलाइन्स

  1. कोई ट्रैकिंग नहीं () के रूप में इस्तेमाल करें पढ़ने के लिए केवल पढ़ने के लिए
  2. N+1 प्रविष्टियों से दूर रहें - उपयोग Include() या विभाजन उचित रूप से
  3. कम्पाइल्ड शब्दकोश इस्तेमाल करें बार बार क्वैरी पैटर्न के लिए
  4. डिज़िटिटिक्स पर विचार करें? पेचीदा चीज़ों से दूर रहने का मतलब है कार्टियन उत्पादों से दूर रहना
  5. प्रचयन इस्तेमाल करें बहुत से प्रविष्ट/व्यस्त तिथि के लिए
  6. परियोजना से DTOs डाटा ट्रांसफर व स्मृति प्रयोग को कम करने के लिए शुरू
  7. शाफ्स अद्यतन/ मिटाने का काम करता है (ईएफ कोर 7+) बड़ी संक्रियाों के लिए
  8. केंद्रित एसक्यूएल हमेशा लॉग तथा समीक्षा करें विकास में

जब एसक्यूएल के साथ काम करता है

  1. पूर्ण पाठ खोज का प्रयोग करें विशेषताएँ (y)मेरी गाइडके बदले ) LIKE चर
  2. एलएसपीएस- बी स्तम्भ एम्बेडेड स्कीमा डाटा के लिए
  3. ऐरे प्रकार उपयोग करें निगम के भीतर संग्रह के लिए
  4. कनेक्शन पूलिंग कॉन्फ़िगर करेंName आपके कार्य के लिए उचित रूप से लोड करें
  5. अपनी निर्देशिका tsvector स्तंभ संगठनों के साथ
  6. सीमा क़िस्म इस्तेमाल करें तारीख़/ समय सीमा के लिए

भाग 2 में आ रहा है

अगले लेख में, हम खोजेंगे:

  • लागू करें: माइक्रो- पायथन मेल जगह
  • रॉडी- पाठ/ नजीफ़ल: अधिकतम प्रदर्शन तथा नियंत्रण
  • ऑब्जेक्ट मैपिंग लाइब्रेरी: मेस्टर वी- मैपपर
  • हाइब्रिएशनेस: दबा रहे ईएफ तथा डीआरएस पैटर्न को जोड़ा जा रहा है (सीक्यूएस पैटर्न)
  • परफ़ॉर्मेंस मारकमार्क्स: वास्तविक विश्व तुलना
  • निर्णय मैट्रिक्स: अपने अनुभव के लिए सही औज़ार चुनना

सन्दर्भ और अन्य पठन

इस ब्लॉग पर संबंधित आलेख:


भाग 2 में, हम Dapppsse, रॉ Npsqucqul में कटौती करेंगे, और जांच करें कि कैसे बहुतम प्रदर्शन के लिए और बनाए रखने के लिए।

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.