# डाटा एक्सेस : ओ एक्सप्रेशन तथा मैपिंग ( पार्ट 2 - tappser, एसक्यूएल, और Hyybd पूछताछेस)

<!-- category -- .NET, Dapper, PostgreSQL, Performance, Database -->
<datetime class="hidden">2025-12-03T15:00</datetime>

हमारे विस्तृत गाइड के भाग में आपका स्वागत है .ENT में डेटा पहुँच के लिए! [पार्ट 1](/blog/orm-mapping-comparison-part1)हमने पूछा कि क्या हम किसी भी देश में जाकर बसने के लिए तैयार हैं ।

इस लेख में, हम हल्का-छोटे विकल्प का पता लगा लेंगे और कैसे कई साथ मिलकर प्रदर्शन के लिए गुणा करें:

- **[लागू करें](https://github.com/DapperLib/Dapper)**: माइक्रो- पायथन मेल जगह
- **रॉ एडवेड. लेबल/[नीग](https://www.npgsql.org/)**: अधिकतम प्रदर्शन तथा नियंत्रण
- **ऑब्जेक्ट मैपिंग लाइब्रेरी**: [मैपस्टर](https://github.com/MapsterMapper/Mapster) वी. [स्वचलित- मैपपर](https://automapper.org/)
- **हाइब्रिएशनेस**: दबा रहे ईएफ तथा डीआरएस पैटर्न को जोड़ा जा रहा है (सीक्यूएस पैटर्न)
- **परफ़ॉर्मेंस मारकमार्क्स**: वास्तविक विश्व तुलना
- **निर्णय मैट्रिक्स**: अपने अनुभव के लिए सही औज़ार चुनना

## विषय - सूची

## डी- हॉर: माइक्रो- ओ पायथन

[लागू करें](https://github.com/DapperLib/Dapper) यह एक हल्का, उच्च- अव्वल- व्यू है जोर अतिरेक के द्वारा बनाया गया माइक्रो- व्यू. यह एक पतली परत प्रदान करता है एडॉओ पर एक पतली परत प्रदान करता है.ET, फिल्टरों के बहुमोल कार्य को नियंत्रित करने के लिए परिणाम वस्तुओं को नियंत्रित करता है जबकि आपको एसक्यूएल नियंत्रण पूरा कर देता है.

### क्यों कर्टर अस्तित्व में है

Dapper के लिए प्रधान-प्रयोग डाटा पहुँच की आवश्यकता के बाहर पैदा किया गया था. टीम ने पाया कि पूर्ण ओ-रे-र (प्रयोगीय घटना) के लिए बहुत अधिक Bapons (pon-pon-pons) जोड़ा. Dapper आपको कुल सुविधा सिर्फ 515% के साथ केवल 515% soways.

### कुंजी फीचर

- **एसक्यूएल**: आप सभी एसक्यूएल को अपने आप पर पूरा नियंत्रण रखते हैं
- **उच्च परफार्मेंस**: टैक्सस के ऊपर न्यूनतम टेटनस. NERT (5- 15%)
- **मल्टी- एमिंग**: बहुत से संबंधित प्रकारों को मैप करें
- **पैरामीटर हैंडलिंग**: स्वचालित पैरामीटरीकरण एसक्यूएल इन्जेक्शन से रोकता है
- **लेन देन समर्थन**: ट्रांजेक्शन पर पूरा नियंत्रण
- **सिमुलेटिकता**: कोई कॉन्फ़िगरेशन नहीं, ट्रैक बदलना नहीं, कोई जादू नहीं
- **अस्सित/A URI**: आज के लिए पूर्ण अतुल्यकालिक समर्थन

### मूल डीकेकर उदाहरण

```csharp
using Npgsql;
using Dapper;

public class DapperBlogRepository
{
    private readonly string _connectionString;

    public DapperBlogRepository(string connectionString)
    {
        _connectionString = connectionString;

        // Configure Dapper to work with PostgreSQL naming conventions
        DefaultTypeMap.MatchNamesWithUnderscores = true;
    }

    // Simple query
    public async Task<IEnumerable<BlogPost>> GetRecentPostsAsync(int count)
    {
        using var connection = new NpgsqlConnection(_connectionString);

        const string sql = @"
            SELECT id, title, content, tags, published_date, category_id
            FROM blog_posts
            ORDER BY published_date DESC
            LIMIT @Count";

        return await connection.QueryAsync<BlogPost>(sql, new { Count = count });
    }

    // Query with WHERE clause
    public async Task<BlogPost> GetPostByIdAsync(int id)
    {
        using var connection = new NpgsqlConnection(_connectionString);

        const string sql = @"
            SELECT id, title, content, published_date
            FROM blog_posts
            WHERE id = @Id";

        return await connection.QueryFirstOrDefaultAsync<BlogPost>(sql, new { Id = id });
    }

    // Insert with returning ID
    public async Task<int> CreatePostAsync(BlogPost post)
    {
        using var connection = new NpgsqlConnection(_connectionString);

        const string sql = @"
            INSERT INTO blog_posts (title, content, published_date, category_id)
            VALUES (@Title, @Content, @PublishedDate, @CategoryId)
            RETURNING id";

        return await connection.ExecuteScalarAsync<int>(sql, post);
    }

    // Update
    public async Task UpdatePostAsync(BlogPost post)
    {
        using var connection = new NpgsqlConnection(_connectionString);

        const string sql = @"
            UPDATE blog_posts
            SET title = @Title,
                content = @Content,
                published_date = @PublishedDate
            WHERE id = @Id";

        await connection.ExecuteAsync(sql, post);
    }

    // Delete
    public async Task DeletePostAsync(int id)
    {
        using var connection = new NpgsqlConnection(_connectionString);

        const string sql = "DELETE FROM blog_posts WHERE id = @Id";

        await connection.ExecuteAsync(sql, new { Id = id });
    }
}
```

### मल्टी- mिंग: शामिल हों

डी-सेर की सबसे शक्तिशाली विशेषताओं में से एक है बहु-मैपिंग - विविध संबंधित वस्तुओं में शामिल होने तथा उन्हें प्रतिरूपित करने के लिए:

```csharp
public async Task<IEnumerable<BlogPost>> GetPostsWithCategoryAsync()
{
    using var connection = new NpgsqlConnection(_connectionString);

    const string sql = @"
        SELECT
            p.id, p.title, p.content, p.published_date,
            c.id, c.name, c.description
        FROM blog_posts p
        INNER JOIN categories c ON p.category_id = c.id
        ORDER BY p.published_date DESC";

    return await connection.QueryAsync<BlogPost, Category, BlogPost>(
        sql,
        (post, category) =>
        {
            post.Category = category;
            return post;
        },
        splitOn: "id"  // Split at the second "id" column
    );
}

// More complex: Posts with comments
public async Task<IEnumerable<BlogPost>> GetPostsWithCommentsAsync()
{
    using var connection = new NpgsqlConnection(_connectionString);

    const string sql = @"
        SELECT
            p.id, p.title, p.content,
            c.id, c.author, c.content, c.created_at
        FROM blog_posts p
        LEFT JOIN comments c ON p.id = c.blog_post_id
        ORDER BY p.published_date DESC, c.created_at";

    var postDict = new Dictionary<int, BlogPost>();

    await connection.QueryAsync<BlogPost, Comment, BlogPost>(
        sql,
        (post, comment) =>
        {
            if (!postDict.TryGetValue(post.Id, out var existingPost))
            {
                existingPost = post;
                existingPost.Comments = new List<Comment>();
                postDict.Add(post.Id, existingPost);
            }

            if (comment != null)
            {
                existingPost.Comments.Add(comment);
            }

            return existingPost;
        },
        splitOn: "id"
    );

    return postDict.Values;
}
```

### विस्तृत डॉकर टेकक

**जटिल क्वीअर के लिए गतिशील पैरामीटर्सः**

```csharp
public async Task<IEnumerable<BlogPost>> SearchWithDynamicFiltersAsync(SearchCriteria criteria)
{
    using var connection = new NpgsqlConnection(_connectionString);

    var parameters = new DynamicParameters();
    var conditions = new List<string>();

    var sql = new StringBuilder("SELECT * FROM blog_posts");

    if (!string.IsNullOrEmpty(criteria.SearchTerm))
    {
        conditions.Add("search_vector @@ to_tsquery('english', @SearchTerm)");
        parameters.Add("SearchTerm", criteria.SearchTerm);
    }

    if (criteria.CategoryIds?.Any() == true)
    {
        conditions.Add("category_id = ANY(@CategoryIds)");
        parameters.Add("CategoryIds", criteria.CategoryIds);
    }

    if (criteria.FromDate.HasValue)
    {
        conditions.Add("published_date >= @FromDate");
        parameters.Add("FromDate", criteria.FromDate.Value);
    }

    if (criteria.Tags?.Any() == true)
    {
        conditions.Add("tags && @Tags");  // PostgreSQL array overlap
        parameters.Add("Tags", criteria.Tags);
    }

    if (conditions.Any())
    {
        sql.Append(" WHERE ");
        sql.Append(string.Join(" AND ", conditions));
    }

    sql.Append(" ORDER BY published_date DESC LIMIT @Limit");
    parameters.Add("Limit", criteria.Limit);

    return await connection.QueryAsync<BlogPost>(sql.ToString(), parameters);
}
```

**मनपसंद क़िस्म लागू करने के लिए:**

```csharp
// Handle PostgreSQL arrays
public class PostgresArrayTypeHandler : SqlMapper.TypeHandler<string[]>
{
    public override void SetValue(IDbDataParameter parameter, string[] value)
    {
        parameter.Value = value;
        ((NpgsqlParameter)parameter).NpgsqlDbType = NpgsqlDbType.Array | NpgsqlDbType.Text;
    }

    public override string[] Parse(object value)
    {
        return (string[])value;
    }
}

// Handle PostgreSQL JSONB
public class JsonTypeHandler<T> : SqlMapper.TypeHandler<T>
{
    public override void SetValue(IDbDataParameter parameter, T value)
    {
        parameter.Value = JsonSerializer.Serialize(value);
        ((NpgsqlParameter)parameter).NpgsqlDbType = NpgsqlDbType.Jsonb;
    }

    public override T Parse(object value)
    {
        return JsonSerializer.Deserialize<T>(value.ToString());
    }
}

// Register handlers (in startup)
SqlMapper.AddTypeHandler(new PostgresArrayTypeHandler());
SqlMapper.AddTypeHandler(new JsonTypeHandler<Dictionary<string, object>>());
```

**उपयोग किए गए प्रश्नों के साथ बल्क संचालन:**

```csharp
public async Task BulkInsertPostsAsync(IEnumerable<BlogPost> posts)
{
    using var connection = new NpgsqlConnection(_connectionString);
    await connection.OpenAsync();

    using var writer = await connection.BeginBinaryImportAsync(
        "COPY blog_posts (title, content, tags, published_date) FROM STDIN (FORMAT BINARY)"
    );

    foreach (var post in posts)
    {
        await writer.StartRowAsync();
        await writer.WriteAsync(post.Title);
        await writer.WriteAsync(post.Content);
        await writer.WriteAsync(post.Tags, NpgsqlDbType.Array | NpgsqlDbType.Text);
        await writer.WriteAsync(post.PublishedDate);
    }

    await writer.CompleteAsync();
}
```

**लेन देन समर्थन:**

```csharp
public async Task TransferPostToCategoryAsync(int postId, int newCategoryId)
{
    using var connection = new NpgsqlConnection(_connectionString);
    await connection.OpenAsync();

    using var transaction = await connection.BeginTransactionAsync();

    try
    {
        // Update the post
        await connection.ExecuteAsync(
            "UPDATE blog_posts SET category_id = @CategoryId WHERE id = @PostId",
            new { CategoryId = newCategoryId, PostId = postId },
            transaction
        );

        // Log the change
        await connection.ExecuteAsync(
            @"INSERT INTO category_history (post_id, category_id, changed_at)
              VALUES (@PostId, @CategoryId, @ChangedAt)",
            new { PostId = postId, CategoryId = newCategoryId, ChangedAt = DateTime.UtcNow },
            transaction
        );

        await transaction.CommitAsync();
    }
    catch
    {
        await transaction.RollbackAsync();
        throw;
    }
}
```

### डीकर इस्तेमाल करते वक्‍त

**सँभालकर का प्रयोग जब:**

- परफार्मेंस गंभीर है लेकिन आपको निरपेक्ष अधिकतम गति की आवश्यकता नहीं है
- आप सहज लेखन हैं एसक्यूएल
- आपके पास जटिल बातें हैं जो LNONQ के लिए ठीक से नक्शा नहीं है
- आपको एसक्यूएल पीढ़ी पर बढ़िया नियंत्रण की आवश्यकता है
- आप एक मौजूदा डाटाबेस स्कीमा के साथ काम कर रहे हैं
- आप कम से कम न्यूनतम तथा निर्भरता चाहते हैं
- स्मृति प्रयोग एक चिंता है
- आपको बिन बुलाए डाटाबेस विशिष्ट विशेषताओं को जमा करना होगा

**जब कोई आपको ठेस पहुँचाता है, तो उसे माफ मत कीजिए:**

- आपका टीम एसक्यूएल के साथ सहज नहीं है
- आप स्वचालित परिवर्तनिंग की जरूरत है
- आप कोड के रूप में स्कीमा उत्प्रवासन चाहते हैं
- आप एक तेजी से व्यवस्थित स्कीमा है
- आपको क्रास- डाटा बेस पोर्ट उपयोगिता की आवश्यकता है
- आपने LNONQ को एसक्यूएल सिंटेक्स पर पसंद किया

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

- **परफार्मेंस क्वैरी करें**: 5-15% कवर रॉडॉड पर कवर.
- **मेमोरी उपयोग**: न्यूनतम - कोई परिवर्तन नहीं ट्रैक या प्रॉक्सी
- **बल्क संचालन**: ज्लोटी के साथ उत्कृष्ट
- **प्रथम क्वैरी**: तीव्र - कोई अप अपॉइंट चरण नहीं
- **डेवलपर उत्पादGenericName**: एसक्यूएल ज्ञान की आवश्यकता है लेकिन बहुत अनुमान योग्य है

## रॉ ई- मेल

पूर्ण अधिकतम प्रदर्शन और नियंत्रण के लिए, आप इस्तेमाल कर सकते हैं [नीग](https://www.npgsql.org/) किसी भी ओलिंक परत के बगैर सीधे.

### जब कुछ अक्षर निकाले जाते हैं, तो बुद्धि से काम लेना

जब कुछ अक्षर हों, तब कुछ नहीं किया जाना चाहिए: (a)

- आप प्रदर्शन के हर कौशल की जरूरत है
- आप उच्च-पार डाटा प्रक्रिया का निर्माण कर रहे हैं
- आप एसक्यूएल विशिष्ट विशेषताओं के साथ काम कर रहे हैं ओलिंक द्वारा समर्थित नहीं है
- आपको स्मृति संभाजन पर सटीक नियंत्रण की आवश्यकता है
- आप बड़ी मात्रा में क्रिया कर रहे हैं या बड़ी डेटासेटिंग कर रहे हैं

### उदाहरण: शुद्ध नीफर

```csharp
public class NpgsqlBlogRepository
{
    private readonly string _connectionString;

    public async Task<List<BlogPost>> GetRecentPostsAsync(int count)
    {
        var posts = new List<BlogPost>();

        using var connection = new NpgsqlConnection(_connectionString);
        await connection.OpenAsync();

        using var command = new NpgsqlCommand(
            "SELECT id, title, content, tags, published_date FROM blog_posts ORDER BY published_date DESC LIMIT @count",
            connection
        );

        command.Parameters.AddWithValue("count", count);

        using var reader = await command.ExecuteReaderAsync();

        while (await reader.ReadAsync())
        {
            posts.Add(new BlogPost
            {
                Id = reader.GetInt32(0),
                Title = reader.GetString(1),
                Content = reader.GetString(2),
                Tags = reader.GetFieldValue<string[]>(3),
                PublishedDate = reader.GetDateTime(4)
            });
        }

        return posts;
    }

    // Using prepared statements for repeated queries
    public async Task<BlogPost> GetPostByIdAsync(int id)
    {
        using var connection = new NpgsqlConnection(_connectionString);
        await connection.OpenAsync();

        using var command = new NpgsqlCommand(
            "SELECT id, title, content FROM blog_posts WHERE id = $1",
            connection
        );

        command.Parameters.AddWithValue(id);
        await command.PrepareAsync(); // Prepared statement for performance

        using var reader = await command.ExecuteReaderAsync();

        if (await reader.ReadAsync())
        {
            return new BlogPost
            {
                Id = reader.GetInt32(0),
                Title = reader.GetString(1),
                Content = reader.GetString(2)
            };
        }

        return null;
    }

    // Working with PostgreSQL JSONB
    public async Task<Dictionary<string, object>> GetPostMetadataAsync(int id)
    {
        using var connection = new NpgsqlConnection(_connectionString);
        await connection.OpenAsync();

        using var command = new NpgsqlCommand(
            "SELECT metadata FROM blog_posts WHERE id = $1",
            connection
        );

        command.Parameters.AddWithValue(id);

        var json = await command.ExecuteScalarAsync() as string;
        return JsonSerializer.Deserialize<Dictionary<string, object>>(json);
    }

    // Streaming large result sets
    public async IAsyncEnumerable<BlogPost> StreamAllPostsAsync()
    {
        using var connection = new NpgsqlConnection(_connectionString);
        await connection.OpenAsync();

        using var command = new NpgsqlCommand(
            "SELECT id, title, content FROM blog_posts ORDER BY id",
            connection
        );

        using var reader = await command.ExecuteReaderAsync();

        while (await reader.ReadAsync())
        {
            yield return new BlogPost
            {
                Id = reader.GetInt32(0),
                Title = reader.GetString(1),
                Content = reader.GetString(2)
            };
        }
    }
}
```

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

- **परफार्मेंस क्वैरी करें**: बेसलाइन - तेज संभव
- **मेमोरी उपयोग**: एवर्स पर निम्नतम - पूर्ण नियंत्रण
- **बल्क संचालन**: स्थिर प्रोटोकॉल के साथ उत्कृष्ट
- **डेवलपर उत्पादGenericName**: सबसे अधिक मैनुअल काम की आवश्यकता है

## ऑब्जेक्ट मैपिंग लाइब्रेरी

DTOCT के साथ काम करते समय, आपको विभिन्न वस्तुओं प्रतिनिधित्वों के बीच नक्शे की जरूरत होती है (डीटीओ, केंद्रों, दृश्य मॉडलों को देखने के लिए. बहुत से पुस्तकालय इस पर ऑटोप कर सकते हैं.

### नक्शाः उच्च- आकार मैपिंग

[मैपस्टर](https://github.com/MapsterMapper/Mapster) यह एक तेजी से, अधिवेशन आधारित वस्तु मैपर है जो स्रोत पीढ़ी का उपयोग करता है।

```csharp
// Install: Mapster and Mapster.Tool
using Mapster;

public class BlogPostDto
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Summary { get; set; }
    public List<string> CategoryNames { get; set; }
}

public class BlogPost
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public List<Category> Categories { get; set; }
}

// Configuration
public class MappingConfig : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        config.NewConfig<BlogPost, BlogPostDto>()
            .Map(dest => dest.Summary, src => src.Content.Substring(0, Math.Min(200, src.Content.Length)))
            .Map(dest => dest.CategoryNames, src => src.Categories.Select(c => c.Name).ToList());

        // Reverse map with ignore
        config.NewConfig<BlogPostDto, BlogPost>()
            .Ignore(dest => dest.Content);
    }
}

// Registration in Program.cs
TypeAdapterConfig.GlobalSettings.Scan(Assembly.GetExecutingAssembly());

// Usage with Dapper
public class BlogService
{
    private readonly string _connectionString;

    public async Task<List<BlogPostDto>> GetPostsAsync()
    {
        using var connection = new NpgsqlConnection(_connectionString);

        var posts = await connection.QueryAsync<BlogPost>(@"
            SELECT p.id, p.title, p.content
            FROM blog_posts p
        ");

        // Map to DTOs - very fast with Mapster
        return posts.Adapt<List<BlogPostDto>>();
    }

    // Projection mapping (compile-time)
    public async Task<List<BlogPostDto>> GetPostsDtosDirectlyAsync()
    {
        using var connection = new NpgsqlConnection(_connectionString);

        // Query directly to DTO shape
        return (await connection.QueryAsync<BlogPostDto>(@"
            SELECT
                id,
                title,
                SUBSTRING(content, 1, 200) as summary
            FROM blog_posts
        ")).ToList();
    }
}
```

### स्वचालित- मानचित्र

[स्वचलित- मैपपर](https://automapper.org/) सबसे लोकप्रिय फिल्टर लाइब्रेरी है, हालांकि नक्शास्टर से धीमी है.

```csharp
// Install: AutoMapper and AutoMapper.Extensions.Microsoft.DependencyInjection
using AutoMapper;

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<BlogPost, BlogPostDto>()
            .ForMember(d => d.Summary, opt => opt.MapFrom(s =>
                s.Content.Length > 200 ? s.Content.Substring(0, 200) : s.Content))
            .ForMember(d => d.CategoryNames, opt => opt.MapFrom(s =>
                s.Categories.Select(c => c.Name)));

        // Reverse map
        CreateMap<BlogPostDto, BlogPost>()
            .ForMember(d => d.Content, opt => opt.Ignore());
    }
}

// Registration in Program.cs
services.AddAutoMapper(typeof(MappingProfile));

// Usage
public class BlogService
{
    private readonly IMapper _mapper;
    private readonly string _connectionString;

    public BlogService(IMapper mapper, IConfiguration configuration)
    {
        _mapper = mapper;
        _connectionString = configuration.GetConnectionString("DefaultConnection");
    }

    public async Task<List<BlogPostDto>> GetPostsAsync()
    {
        using var connection = new NpgsqlConnection(_connectionString);

        var posts = await connection.QueryAsync<BlogPost>(@"
            SELECT id, title, content FROM blog_posts
        ");

        return _mapper.Map<List<BlogPostDto>>(posts.ToList());
    }
}
```

### हस्तचालित मैपिंग: पूरा नियंत्रण

कभी - कभी सबसे अच्छा तरीका साफ प्रदर्शन होता है:

```csharp
public static class BlogPostMapper
{
    public static BlogPostDto ToDto(this BlogPost post)
    {
        return new BlogPostDto
        {
            Id = post.Id,
            Title = post.Title,
            Summary = post.Content.Length > 200
                ? post.Content.Substring(0, 200) + "..."
                : post.Content,
            CategoryNames = post.Categories?.Select(c => c.Name).ToList() ?? new List<string>()
        };
    }

    public static List<BlogPostDto> ToDtoList(this IEnumerable<BlogPost> posts)
    {
        return posts.Select(p => p.ToDto()).ToList();
    }

    // Inline mapping for simple cases
    public static BlogPostDto MapToDto(BlogPost post) => new()
    {
        Id = post.Id,
        Title = post.Title,
        Summary = post.Content[..Math.Min(200, post.Content.Length)]
    };
}

// Usage
var posts = await _repository.GetAllPostsAsync();
var dtos = posts.ToDtoList();
```

### मैपिंग परफ़ॉर्मेंस तुलना@ info: whatsthis

```
BenchmarkDotNet Results (mapping 1000 objects):

Method              | Mean      | Allocated
--------------------|-----------|----------
Manual Mapping      | 45.2 μs   | 78 KB
Mapster             | 52.1 μs   | 79 KB
AutoMapper          | 184.3 μs  | 156 KB
```

**कुंजी लेसर:**

- हस्तचालित फिल्टरिंग तेजी से है लेकिन अधिक कोड की आवश्यकता है
- नक्शा लगभग कम कोड के साथ तेज के रूप में है
- स्वतः- मानचित्रपर सुविधाजनक है लेकिन उसके ऊपर ऊपर ऊपर ऊपरी खड़ा होता है

## इस सवाल का जवाब: सारी दुनिया में सबसे बढ़िया

असल अनुप्रयोग में, आप अकसर एक ही अनुप्रयोग के अन्दर अलग - अलग परिस्थितियों का उपयोग करना चाहते हैं । **दिशा पास किये जाने वाले प्रश्न** सबसे उत्पादन सिस्टम के लिए.

### सीक्यूएस पैटर्न: अलग पढ़ना तथा लिखना

सीक्यूआरएस (अंग्रेजी ज़िम्मेदारी का ऐलान) पैटर्न स्वाभाविक है, जो कि पैदाइशी डाटा पहुँच के लिए उपयुक्त है. सीक्यूएस और घटना के साथ प्रचण के लिए [मारटेन](https://martendb.io/), मेरे लेख को देखिए [आधुनिक CERS और घटनाएँ](/blog/moderncqrsandeventsourcing).

**मार्टन इस चर्चा से कैसे पता चलता है:**

मार्टेटन एक दस्तावेज़ डाटाबेस है और यह घटना कि एसक्यूएल पर बनाया गया है जो कि ग्रोन डाटा पहुँच को किसी अन्य स्तर पर ले जाता है. यह जोड़ता है:

- **घटना ईगलिंग** लिखने के लिए (मत्तीमय घटना नहरें)
- **परियोजना** पढ़ने के लिए (डिप्रायित दृश्यों के लिए आवश्यक हैं)
- **केआईओस्लेव का JSONB** दस्तावेज़ भंडारण के लिए
- अंतर्निर्मित सीक्यूआरएस पैटर्न

इस लेख में पारंपरिक संबंधयों की पहुँच पर ध्यान दिया गया है (एएफ कोर, डीप्पन), मार्टेन बताता है कि आप किस तरह के उपयोग कर सकते हैं?

- अलग लिखने के मॉडल ( ट्रांजेक्शन तथा संगतता के लिए अलग किए गए)
- अलग पढ़ने के मॉडल (कंक और प्रदर्शन के लिए अलग किए गए)
- प्रत्येक कार्य के लिए उचित औज़ार इस्तेमाल करें

```mermaid
graph TB
    Client[Client Application]

    subgraph "Write Side - Commands"
        WriteAPI[Write API / Commands]
        EFCore[EF Core Context]
        WriteDB[(PostgreSQL<br/>Write Operations)]
    end

    subgraph "Read Side - Queries"
        ReadAPI[Read API / Queries]
        Dapper[Dapper Repository]
        ReadDB[(PostgreSQL<br/>Read Operations)]
    end

    Client -->|Create/Update/Delete| WriteAPI
    WriteAPI --> EFCore
    EFCore -->|Change Tracking<br/>Validation<br/>Business Logic| WriteDB

    Client -->|Query/Search| ReadAPI
    ReadAPI --> Dapper
    Dapper -->|Optimized SQL<br/>DTOs<br/>No Tracking| ReadDB

    WriteDB -.->|Same Database| ReadDB

    style Client stroke:#6366f1,stroke-width:2px
    style WriteAPI stroke:#2563eb,stroke-width:2px
    style EFCore stroke:#2563eb,stroke-width:2px
    style WriteDB stroke:#2563eb,stroke-width:2px
    style ReadAPI stroke:#059669,stroke-width:2px
    style Dapper stroke:#059669,stroke-width:2px
    style ReadDB stroke:#059669,stroke-width:2px
```

इस पैटर्न से लाभ प्राप्त होता है:

- **ईएफ कोर** लिखने के लिए: ट्रैक, वैधीकरण, व्यापार नियम बदलें
- **लागू करें** पढ़ने के लिए: अधिकतम क्वैरी प्रदर्शन तथा समर्थता
- एक ही डाटाबेस, प्रत्येक प्रसंग के लिए भिन्न पहुँच पैटर्न एडजस्ट्ड

### कार्यान्वयन: CQRRS कोर तथा डीपेर के साथ

```csharp
// Commands: Use EF Core for change tracking and validation
public class BlogCommandService
{
    private readonly BlogDbContext _context;
    private readonly ILogger<BlogCommandService> _logger;

    public BlogCommandService(BlogDbContext context, ILogger<BlogCommandService> logger)
    {
        _context = context;
        _logger = logger;
    }

    public async Task<int> CreatePostAsync(CreatePostCommand command)
    {
        // Business logic and validation
        var post = new BlogPost
        {
            Title = command.Title,
            Content = command.Content,
            CategoryId = command.CategoryId,
            PublishedDate = DateTime.UtcNow
        };

        _context.BlogPosts.Add(post);
        await _context.SaveChangesAsync();

        _logger.LogInformation("Created blog post {PostId}", post.Id);

        return post.Id;
    }

    public async Task UpdatePostAsync(UpdatePostCommand command)
    {
        var post = await _context.BlogPosts.FindAsync(command.Id);

        if (post == null)
            throw new InvalidOperationException($"Post {command.Id} not found");

        post.Title = command.Title;
        post.Content = command.Content;
        post.UpdatedAt = DateTime.UtcNow;

        await _context.SaveChangesAsync();

        _logger.LogInformation("Updated blog post {PostId}", post.Id);
    }

    public async Task DeletePostAsync(int id)
    {
        var post = await _context.BlogPosts.FindAsync(id);

        if (post != null)
        {
            _context.BlogPosts.Remove(post);
            await _context.SaveChangesAsync();

            _logger.LogInformation("Deleted blog post {PostId}", id);
        }
    }
}

// Queries: Use Dapper for read performance
public class BlogQueryService
{
    private readonly string _connectionString;
    private readonly ILogger<BlogQueryService> _logger;

    public BlogQueryService(IConfiguration configuration, ILogger<BlogQueryService> logger)
    {
        _connectionString = configuration.GetConnectionString("DefaultConnection");
        _logger = logger;
    }

    public async Task<BlogPostDto> GetPostBySlugAsync(string slug)
    {
        using var connection = new NpgsqlConnection(_connectionString);

        const string sql = @"
            SELECT
                p.id,
                p.title,
                p.slug,
                p.content,
                p.published_date,
                c.id as category_id,
                c.name as category_name,
                (SELECT COUNT(*) FROM comments WHERE blog_post_id = p.id) as comment_count
            FROM blog_posts p
            INNER JOIN categories c ON p.category_id = c.id
            WHERE p.slug = @Slug";

        var post = await connection.QueryFirstOrDefaultAsync<BlogPostDto>(sql, new { Slug = slug });

        if (post != null)
        {
            _logger.LogInformation("Retrieved blog post by slug {Slug}", slug);
        }

        return post;
    }

    public async Task<PagedResult<BlogPostSummaryDto>> GetRecentPostsAsync(int page, int pageSize)
    {
        using var connection = new NpgsqlConnection(_connectionString);

        const string sql = @"
            SELECT
                p.id,
                p.title,
                p.slug,
                LEFT(p.content, 200) as summary,
                p.published_date,
                c.name as category_name
            FROM blog_posts p
            INNER JOIN categories c ON p.category_id = c.id
            ORDER BY p.published_date DESC
            LIMIT @PageSize OFFSET @Offset";

        const string countSql = "SELECT COUNT(*) FROM blog_posts";

        var posts = await connection.QueryAsync<BlogPostSummaryDto>(
            sql,
            new { PageSize = pageSize, Offset = (page - 1) * pageSize }
        );

        var totalCount = await connection.ExecuteScalarAsync<int>(countSql);

        return new PagedResult<BlogPostSummaryDto>
        {
            Items = posts.ToList(),
            TotalCount = totalCount,
            Page = page,
            PageSize = pageSize
        };
    }

    public async Task<List<BlogPostDto>> SearchPostsAsync(string searchTerm)
    {
        using var connection = new NpgsqlConnection(_connectionString);

        const string sql = @"
            SELECT
                p.id,
                p.title,
                p.slug,
                p.content,
                p.published_date,
                c.name as category_name,
                ts_rank(p.search_vector, query) as relevance_score
            FROM blog_posts p
            INNER JOIN categories c ON p.category_id = c.id,
                 to_tsquery('english', @SearchTerm) query
            WHERE p.search_vector @@ query
            ORDER BY relevance_score DESC
            LIMIT 50";

        var posts = await connection.QueryAsync<BlogPostDto>(sql, new { SearchTerm = searchTerm });

        _logger.LogInformation(
            "Searched posts with term {SearchTerm}, found {Count} results",
            searchTerm,
            posts.Count()
        );

        return posts.ToList();
    }
}

// Service layer orchestrating commands and queries
public class BlogService
{
    private readonly BlogCommandService _commands;
    private readonly BlogQueryService _queries;

    public BlogService(BlogCommandService commands, BlogQueryService queries)
    {
        _commands = commands;
        _queries = queries;
    }

    // Write operations delegate to command service
    public Task<int> CreatePostAsync(CreatePostCommand command) => _commands.CreatePostAsync(command);
    public Task UpdatePostAsync(UpdatePostCommand command) => _commands.UpdatePostAsync(command);
    public Task DeletePostAsync(int id) => _commands.DeletePostAsync(id);

    // Read operations delegate to query service
    public Task<BlogPostDto> GetPostBySlugAsync(string slug) => _queries.GetPostBySlugAsync(slug);
    public Task<PagedResult<BlogPostSummaryDto>> GetRecentPostsAsync(int page, int pageSize)
        => _queries.GetRecentPostsAsync(page, pageSize);
    public Task<List<BlogPostDto>> SearchPostsAsync(string searchTerm)
        => _queries.SearchPostsAsync(searchTerm);
}
```

### मौके- आवरण एसक्यूएल के साथ ईएफ कोर

अनुप्रयोगों के लिए जो मुख्य रूप से ईएफ कोर हैं परंतु कभी - कभी कसरत करने की आवश्यकता होती है:

```csharp
public class BlogService
{
    private readonly BlogDbContext _context;

    // 95% of queries: Use EF Core LINQ
    public async Task<List<BlogPost>> GetPostsByCategoryAsync(int categoryId)
    {
        return await _context.BlogPosts
            .Where(p => p.CategoryId == categoryId)
            .Include(p => p.Comments)
            .ToListAsync();
    }

    // 5% of queries: Use raw SQL for complex analytics
    public async Task<List<PostAnalytics>> GetPostAnalyticsAsync()
    {
        using var connection = _context.Database.GetDbConnection();
        await _context.Database.OpenConnectionAsync();

        using var command = connection.CreateCommand();
        command.CommandText = @"
            WITH post_metrics AS (
                SELECT
                    p.id,
                    p.title,
                    COUNT(DISTINCT c.id) as comment_count,
                    COUNT(DISTINCT v.id) as view_count,
                    AVG(c.sentiment_score) as avg_sentiment
                FROM blog_posts p
                LEFT JOIN comments c ON p.id = c.post_id
                LEFT JOIN post_views v ON p.id = v.post_id
                WHERE p.published_date >= NOW() - INTERVAL '30 days'
                GROUP BY p.id, p.title
            )
            SELECT * FROM post_metrics
            ORDER BY view_count DESC";

        var analytics = new List<PostAnalytics>();
        using var reader = await command.ExecuteReaderAsync();

        while (await reader.ReadAsync())
        {
            analytics.Add(new PostAnalytics
            {
                PostId = reader.GetInt32(0),
                Title = reader.GetString(1),
                CommentCount = reader.GetInt64(2),
                ViewCount = reader.GetInt64(3),
                AverageSentiment = reader.IsDBNull(4) ? 0 : reader.GetDouble(4)
            });
        }

        return analytics;
    }
}
```

## परफ़ॉर्मेंस तुलना

चलो असली दुनिया प्रदर्शन प्रदर्शन Stivix के लिए आम आपरेशनों पर देखो:

### बेनचमार्क: 1000 अभिलेखों को पढ़ा जा रहा है

```
BenchmarkDotNet Results (Lower is Better):

Method                    | Mean       | Allocated
------------------------- |----------- |-----------
EF Core (No Tracking)    | 12.34 ms   | 2.4 MB
EF Core (With Tracking)  | 15.67 ms   | 4.8 MB
Dapper                   | 8.21 ms    | 1.8 MB
Raw Npgsql               | 7.45 ms    | 1.2 MB
```

### बेनचमार्क: 1000 अभिलेख प्रविष्ट किया जा रहा है

```
Method                    | Mean       | Allocated
------------------------- |----------- |-----------
EF Core (SaveChanges)    | 245.3 ms   | 15.2 MB
EF Core (BulkInsert)     | 42.1 ms    | 8.4 MB
Dapper (Loop)            | 189.7 ms   | 2.1 MB
Npgsql COPY              | 18.3 ms    | 0.8 MB
```

### बेनचमार्क: जटिल शामिल होते प्रश्न

```
Method                    | Mean       | Allocated
------------------------- |----------- |-----------
EF Core (Include)        | 28.5 ms    | 5.2 MB
EF Core (Split Query)    | 24.1 ms    | 4.8 MB
Dapper (Multi-Map)       | 16.8 ms    | 3.1 MB
Raw Npgsql               | 15.2 ms    | 2.4 MB
```

### कुंजी अगलों को दूर ले जाता है

1. **रॉ Npgl तेजी से है** परंतु अधिक कोड की आवश्यकता है
2. **टाइलर बढ़िया प्रदर्शन प्रस्तुत करता है** कम से कम खर्च के साथ (60-70% ईएफ कोर से अधिक तेजी से)
3. **ईएफ कोर कोई- ट्रैक नहीं** ज़्यादातर घटनाओं के लिए लिहाज़ दिखाना ज़रूरी है
4. **बल्क संचालन** सबसे बड़ा प्रदर्शन प्रतिशत दिखाएँ (१०-13x भिन्‍न!)
5. **मेमोरी एग्रीमेंट्स** एक ऐसे ही नमूने का पालन करें जो कार्यान्वित करने का समय है

## निर्णय: कौन - सी बात उपयोग करने के लिए निकट आती है

### जब:

- एक नया अनुप्रयोग बनाने की आवश्यकताओं के साथ - साथ
- एनआईएस डोमेन- डिगॉन डिजाइन अमीर एंटिटी मॉडलों के साथ
- GNOME के लिए आपको उत्प्रवासन और स्कीमा प्रबंधन की जरूरत है
- V# एसक्यूएल से अधिक सहज टीम है
- STRE रीड/ दोहरा अनुपात संतुलित है
- 20-50% के भीतर STAV क्वैरी प्रदर्शन स्वीकार्य है
- TEXT आप करना चाहते हैं और काम पैटर्न की इकाई बदलना चाहते हैं

देखें [पार्ट 1](/blog/orm-mapping-comparison-part1) जो (ख़ुदा के इल्म में) फेरा जा चुका है अटकल दौड़ाने वाले हलाक हों

### जब:

- परफ़ॉर्मेंस परफ़ॉर्मेंस महत्वपूर्ण है लेकिन महत्वपूर्ण नहीं
- नीचे के लिए नक्शा ठीक से नहीं है कि आपके पास जटिल संरचनाएं हैं
-  आप एसक्यूएल को आराम से लिखने के लिए कर रहे हैं
- 2880 आपको एसक्यूएल पीढ़ी पर बढ़िया नियंत्रण की आवश्यकता है
- मौजूदा डाटाबेस स्कीमा के साथ सत्यापन करता है
- एनआईएस पठन-भारी कार्य सरल लिखता है के साथ लोड होता है
- • आप एक छोटा - सा कपड़ा चाहते हैं

### जब सेः (q)

- न्यूनतम अधिकतम प्रदर्शन गंभीर है
- एंटर डाटा प्रक्रियार का निर्माण
- केआईओस्लेव विशिष्ट विशेषताओं के साथ विस्तृत कार्य
- टॉगल संक्रिया और बड़ी मात्रा में आयात करता है
- हर काम में हाथ बँटाइए ।
- अतिसक्रिय आपको पूर्ण नियंत्रण की आवश्यकता है

### जब आपका बच्चा छोटा होता है तो आप क्या कर सकते हैं?

- अनुप्रयोग के विभिन्न भागों में भिन्न आवश्यकताएं हैं
- तुमने लिखा के लिए डीकेआरआरएस पैटर्न (ईएफएफ कोर) Name
- © अधिकांश जांच EF कोर प्रयोग करती हैं, लेकिन कुछ रॉ एसक्यूएल की जरूरत है
- [ चित्र का श्रेय]
- विविध आवश्यकताओं के साथ भरा बड़ा, जटिल अनुप्रयोग

## सर्वोत्तम अभ्यास सारांश

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

1. **ईएफआर कोर के साथ प्रारंभ करें** नई परियोजना के लिए जब तक आप विशिष्ट प्रदर्शन आवश्यकता नहीं है
2. **एम्बिएशन से पहले प्रोफ़ाइल** - आपको डीपेर/ एसक्यूएल की जरूरत नहीं है
3. **ग्रोन पास होने के लिए इस्तेमाल करें** - विभिन्न औज़ारों की मिलाने की शक्ति
4. **डाटा एक्सेस तर्क अलग रखें** - भंडार पैटर्न कार्यान्वयन को स्विच करने में मदद करता है
5. **कनेक्शन पूलिंग इस्तेमाल करें** - अपने कार्य के लिए उचित रूप से विन्यस्त करें
6. **अनवर्स- एसक्यूएल विशेषताएँ** - शक्तिशाली डाटाबेस क्षमता को एब्सट्रेक्ट नहीं करते

### लागू नहीं किया गया

1. **पैरामीटरों का उपयोग करें** एसक्यूएल इन्जेक्शन को रोकने के लिए
2. **क्वैरी पर विचार कीजिए** महँगाई के लिए, बार - बार सैर
3. **बहु-मैपिंग इस्तेमाल करें** बहुत से राउंड के बजाए शामिल होने के लिए
4. **कनेक्शन फिर से इस्तेमाल करें** कनेक्शन पूल से
5. **डेप्पर पर विचार कीजिए.** साधारण आपरेशनों के लिए

### परफ़ॉर्मेंस हार्डवेयर्स

1. **अपनी प्रविष्टि सूची दें** - विशेषज्ञ के साथ धीमा घटना की जाँच करें
2. **तैयार कथनों का प्रयोग करें** बार- बार की गई चीज़ों के लिए
3. **बैच संचालन** जब संभव हो
4. **कॉपी का प्रयोग करें** महाजोंग में शामिल होने के लिए
5. **कनेक्शन पूल मॉनीटर करें** - न्यूनतम /max पूल आकार विन्यस्त करें
6. **पढ़ने की नकलों पर गौर कीजिए** पढ़ने के लिए भारी कार्य- भार

## कंटेनमेंट

आपके विशिष्ट आवश्यकताओं के लिए उचित डाटा पहुँच का चयन करें. वेरिटी अनुप्रयोग "सबसे सही" उपकरण प्राप्त करने के बारे में नहीं है - यह आपकी विशिष्ट आवश्यकताओं के लिए उचित उपकरण से मेल खाने वाले उपकरण के बारे में है:

- **ईएफ कोर** (देखें) [पार्ट 1](/blog/orm-mapping-comparison-part1)) तेज़ विकास, डोमेन मॉडलिंग, और अनुप्रयोग जहाँ डेवलपर अपिक प्रदर्शन करते हैं
- **लागू करें** पास-चंदी प्रदर्शन तथा उचित रूप से एक बढ़िया मध्य भूमि प्रदान करता है
- **रॉ नॉग** डाटा- इन क्रियाओं के लिए अधिकतम प्रदर्शन तथा नियंत्रण प्रदान करता है
- **मैपिंग लाइब्रेरी** नक्शेस्टर तथा स्वतः- लेवल डाटा एक्सेस के साथ काम करते समय क्लैपलेट को कम करें

अभ्यास में, सबसे सफल अनुप्रयोग प्रायः एक प्रयोग करता है **समझ में आता है**, जहाँ उचित है वहाँ प्रत्येक औज़ार की शक्‍ति का प्रयोग करते हुए:

- प्रयोक्ता **ईएफ कोर** अपने डोमेन तर्क के लिए और लिखता है
- प्रयोक्ता **लागू करें** जटिल पठन और रिपोर्ट के लिए
- प्रयोक्ता **रॉ नॉप** विभिन्न आपरेशनों तथा प्रायोगिक कार्यों के लिए

कुंजी हैः

1. **अपनी माँगों को समझिए** - प्रदर्शन, विकास गति, टीम कौशल
2. **अपने अनुप्रयोग को प्रोफ़ाइल करें** - वास्तविक बोतलों की पहचान, नहीं माना जाता
3. **दिशा निर्धारण चुनें@ info: whatsthis** - अपनी आवश्यकताओं को पूरा करने के लिए आसान उपकरण इस्तेमाल करें
4. **फेरबदल करते रहिए** - आप एक ही अनुप्रयोग के भीतर नज़दीक जा सकते हैं

याद रखिए: समय - समय पर बुराई का मूल है, लेकिन यह एक ऐसी प्रणाली बना रहा है जो ज़रूरत पड़ने पर कम नहीं हो सकती ।

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

**इस सेवर्स का भाग १:**

- [डाटा पहुँच .NT भाग 1: एंटिटीर कोर में](/blog/orm-mapping-comparison-part1)

**रिमोट दस्तावेज़ीकरण:**

- [टाइलर Git](https://github.com/DapperLib/Dapper)
- [सेकर शिक्षण पाठ](https://dapper-tutorial.net/)
- [Npgsqult दस्तावेज़ीकरण](https://www.npgsql.org/doc/)
- [एन. डब्ल्यू.](https://www.npgsql.org/doc/basic-usage.html)
- [मैपस्टर GiB](https://github.com/MapsterMapper/Mapster)
- [स्वचलित- मैपकर दस्तावेज़ीकरण](https://docs.automapper.org/)
- [एसक्यूएल दस्तावेज़ीकरण](https://www.postgresql.org/docs/)

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

- [ब्लॉग पोस्ट के लिए एंटिटी फ्रेमवर्क जोड़े](/blog/addingentityframeworkforblogpostspt1)
- [EF उत्प्रवासन सही दिशा दिखाता है](/blog/efmigrationstherightway)
- [ईएफएस कोर के साथ पूरा पाठ खोज रहा है](/blog/textsearchingpt1)
- [आधुनिक CERS और घटनाएँ](/blog/moderncqrsandeventsourcing)

---


*.ENT में डेटा की पहुँच पर हमारे दो भाग श्रृंखला अंत! हम ईएफ कोर से सब कुछ कच्चे एसक्यूएल के अधिकतम प्रदर्शन को कवर किया है, के साथ सौदा परिणाम के लिए जा रहा व्यावहारिक मार्गदर्शन.*