Ledbim.Mongo 1.2.0

dotnet add package Ledbim.Mongo --version 1.2.0
                    
NuGet\Install-Package Ledbim.Mongo -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Ledbim.Mongo" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ledbim.Mongo" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Ledbim.Mongo" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Ledbim.Mongo --version 1.2.0
                    
#r "nuget: Ledbim.Mongo, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Ledbim.Mongo@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Ledbim.Mongo&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Ledbim.Mongo&version=1.2.0
                    
Install as a Cake Tool

Ledbim.Mongo

<p align="center"> <img src="ledbim_mongo_logo.png" alt="Ledbim.Mongo" width="120" /> </p>

<p align="center"> <strong>MongoDB · Repository Pattern · Soft Delete · Audit Trail · Pagination</strong><br/> Ledbim ekosistemi için MongoDB repository altyapısı. </p>


Kapsam

Ledbim.Mongo paketi şu bileşenleri sağlar:

Bileşen Açıklama
MongoBaseEntity 3 varyantlı base entity — audit alanları ve soft delete dahil
IMongoRepository<T> MongoDB CRUD ve pagination arayüzü
MongoRepository<T> Soft delete, audit trail, bulk operations implementasyonu
AddMongoRepository<T> Collection adı yapılandırılabilen tek satır DI kaydı

Kurulum

dotnet add package Ledbim.Mongo

Bağımlılıklar

MongoDB.Driver                          v3.6.0
Microsoft.Extensions.Configuration      v10.0.0
Ledbim.Core                            (project reference)

Hızlı Başlangıç

1. appsettings.json

{
  "MongoDb": {
    "ConnectionString": "mongodb://localhost:27017",
    "DatabaseName": "MyApp"
  }
}

2. Entity Tanımlama

// En yaygın kullanım — MongoDB ObjectId ile
public class Product : MongoBaseEntityWithObjectId
{
    public string Name { get; set; } = default!;
    public decimal Price { get; set; }
    public string Category { get; set; } = default!;
}

3. Program.cs

// 1. MongoDB altyapısı
builder.Services.AddMongoDb(builder.Configuration);

// 2. ICurrentUserAccessor (audit için zorunlu)
builder.Services.AddScoped<ICurrentUserAccessor, CurrentUserAccessor>();

// 3. Repository kaydı
builder.Services.AddMongoRepository<Product>("products");

4. Handler'da Kullanım

public class GetProductQueryHandler(IMongoRepository<Product> repo)
    : IRequestHandler<GetProductQuery, Result<ProductDto>>
{
    public async Task<Result<ProductDto>> Handle(GetProductQuery request, CancellationToken ct)
    {
        var product = await repo.GetAsync(x => x.Name == request.Name, ct);

        if (product is null)
            return Result<ProductDto>.Fail(ResultType.NotFound, "Ürün bulunamadı.");

        return Result<ProductDto>.Success(ResultType.Success, product.ToDto());
    }
}

Entity Varyantları

Üç farklı base sınıf bulunur — kullanım senaryosuna göre seçilir.

MongoBaseEntity (Id'siz)

public abstract class MongoBaseEntity

Audit ve soft delete alanları içerir, Id içermez. Kendi Id stratejisini tanımlamak isteyen entity'ler için kullanılır.

Alan BSON Adı Açıklama
CreatedDate createdDate Oluşturma tarihi
CreatedBy createdBy Oluşturan kullanıcı
UpdatedDate updatedDate Son güncelleme tarihi
UpdatedBy updatedBy Son güncelleyen kullanıcı
IsDeleted isDeleted Soft delete bayrağı
DeletedDate deletedDate Silinme tarihi
DeletedBy deletedBy Silen kullanıcı

Tüm alanların setter'ı internal'dir — repository dışından doğrudan atama yapılamaz.

MongoBaseEntityWithObjectId

public abstract class MongoBaseEntityWithObjectId : MongoBaseEntity

Standart kullanım — MongoDB'nin native ObjectId tipiyle Id otomatik üretilir.

public class Order : MongoBaseEntityWithObjectId
{
    public Guid CustomerId { get; set; }
    public decimal Total { get; set; }
    public string Status { get; set; } = default!;
}

AddAsync() çağrısında Id default ise ObjectId.GenerateNewId() otomatik atanır.

MongoBaseEntity<TKey>

public abstract class MongoBaseEntity<TKey> : MongoBaseEntity
    where TKey : IEquatable<TKey>

ObjectId dışında farklı Id tipleri kullanmak gerektiğinde (örneğin string, Guid, int):

public class LogEntry : MongoBaseEntity<string>
{
    // Id string tipinde — dışarıdan atanır
    public string Level { get; set; } = default!;
    public string Message { get; set; } = default!;
}

public class Counter : MongoBaseEntity<int>
{
    // Id int tipinde
    public string Key { get; set; } = default!;
    public long Value { get; set; }
}

Hangi varyantı seçmeli?

Senaryo Varyant
Standart MongoDB dokümanı MongoBaseEntityWithObjectId
String veya Guid Id gerekiyor MongoBaseEntity<string> / MongoBaseEntity<Guid>
Id yönetimini tamamen kendin yapacaksın MongoBaseEntity

IMongoRepository<T>

public interface IMongoRepository<T> where T : MongoBaseEntity
{
    // Ekleme
    Task<T> AddAsync(T entity, CancellationToken ct = default);
    Task<IReadOnlyList<T>> AddRangeAsync(IEnumerable<T> entities, CancellationToken ct = default);

    // Güncelleme
    Task<T> UpdateAsync(T entity, CancellationToken ct = default);
    Task UpdateRangeAsync(IEnumerable<T> entities, CancellationToken ct = default);
    Task<long> UpdateManyAsync(
        Expression<Func<T, bool>> predicate,
        UpdateDefinition<T> update,
        CancellationToken ct = default);

    // Silme
    Task DeleteAsync(T entity, CancellationToken ct = default);
    Task DeleteAsync(Expression<Func<T, bool>> predicate, CancellationToken ct = default);
    Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken ct = default);

    // Okuma
    Task<T?> GetAsync(Expression<Func<T, bool>>? predicate = null, CancellationToken ct = default);
    Task<IEnumerable<T>> GetAllAsync(
        Expression<Func<T, bool>>? predicate = null,
        Func<IQueryable<T>, IOrderedQueryable<T>>? orderBy = null,
        CancellationToken ct = default);
    Task<PagedModel<T>> GetAllPagedAsync(MongoPagedFilterRequest<T> filterRequest, CancellationToken ct = default);
    Task<long> GetCountAsync(Expression<Func<T, bool>>? predicate = null, CancellationToken ct = default);

    // Doğrudan collection erişimi
    IMongoCollection<T> Collection { get; }
}

Kullanım Örnekleri

// Tekil kayıt
var product = await repo.GetAsync(x => x.Id == id, ct);

// Koşulla listeleme + sıralama
var products = await repo.GetAllAsync(
    predicate: x => x.Category == "Electronics" && x.Price < 1000,
    orderBy: q => q.OrderByDescending(x => x.Price),
    ct);

// Sayım
var count = await repo.GetCountAsync(x => x.Status == "Active", ct);

// Kısmi güncelleme (UpdateDefinition ile)
var updated = await repo.UpdateManyAsync(
    predicate: x => x.Status == "Draft",
    update: Builders<Product>.Update.Set(x => x.Status, "Published"),
    ct);

// Doğrudan collection — aggregation için
var pipeline = repo.Collection.Aggregate()
    .Match(x => x.Category == "Electronics")
    .Group(x => x.Category, g => new { Category = g.Key, Count = g.Count() });

Soft Delete

Varsayılan olarak tüm okuma sorguları IsDeleted == false filtresi uygular.

// Silinmemiş kayıtları getirir (varsayılan)
var products = await repo.GetAllAsync(x => x.Category == "Electronics");

// Silinmiş kayıtları da dahil et
var request = new MongoPagedFilterRequest<Product>
{
    FilterQuery = new PaginationFilterQuery { PageNumber = 1, PageSize = 20 },
    IgnoreQueryFilters = true   // soft delete bypass
};
var all = await repo.GetAllPagedAsync(request, ct);

Fiziksel silme: Entity IHardDelete implement ederse DeleteAsync() dokümanı veritabanından tamamen kaldırır.

public class TempLog : MongoBaseEntityWithObjectId, IHardDelete
{
    public string Message { get; set; } = default!;
}

// Fiziksel silme gerçekleşir
await repo.DeleteAsync(log, ct);

Audit Trail

AddAsync, UpdateAsync ve DeleteAsync çağrılarında audit alanları otomatik doldurulur. ICurrentUserAccessor DI'ya kayıtlı olmalıdır.

İşlem Doldurulan Alanlar
AddAsync CreatedDate, CreatedBy, UpdatedDate, UpdatedBy
UpdateAsync UpdatedDate, UpdatedBy
DeleteAsync (soft) IsDeleted, DeletedDate, DeletedBy, UpdatedDate, UpdatedBy

ICurrentUserAccessor implementasyonu:

public class CurrentUserAccessor(IHttpContextAccessor httpContextAccessor) : ICurrentUserAccessor
{
    public string? GetCurrentUser()
    {
        return httpContextAccessor.HttpContext?.User
            .FindFirstValue(ClaimTypes.NameIdentifier);
    }
}

// Program.cs
builder.Services.AddScoped<ICurrentUserAccessor, CurrentUserAccessor>();

Pagination

var request = new MongoPagedFilterRequest<Product>
{
    FilterQuery = new PaginationFilterQuery
    {
        PageNumber = 1,
        PageSize = 20
    },
    Predicate = x => x.Category == "Electronics",
    OrderBy = q => q.OrderByDescending(x => x.Price),
    IgnoreQueryFilters = false
};

PagedModel<Product> result = await repo.GetAllPagedAsync(request, ct);

// result.TotalRecords — toplam kayıt sayısı
// result.PagedData    — sayfa verisi

DI Kayıt Detayları

// AddMongoDb overload'ları
services.AddMongoDb(configuration);                   // IConfiguration'dan okur
services.AddMongoDb(settings);                        // MongoDbSettings nesnesi
services.AddMongoDb("mongodb://localhost", "MyDb");   // Direkt parametre

// Repository kaydı
services.AddMongoRepository<Product>();               // Collection adı = "Product"
services.AddMongoRepository<Product>("products");     // Collection adı = "products"
services.AddMongoRepository<Order>("orders");

Kayıt sırası önemlidir:

// 1. Önce MongoDB altyapısı
builder.Services.AddMongoDb(builder.Configuration);

// 2. ICurrentUserAccessor (audit için — AddMongoRepository'den önce)
builder.Services.AddScoped<ICurrentUserAccessor, CurrentUserAccessor>();

// 3. Repository'ler
builder.Services.AddMongoRepository<Product>("products");
builder.Services.AddMongoRepository<Order>("orders");

Tam Kullanım Örneği

// Entity
public class BlogPost : MongoBaseEntityWithObjectId
{
    public string Title { get; set; } = default!;
    public string Content { get; set; } = default!;
    public string AuthorId { get; set; } = default!;
    public string Status { get; set; } = "Draft";
    public List<string> Tags { get; set; } = [];
}

// Command
public record PublishPostCommand(ObjectId PostId) : IRequest<Result>, ICommand;

// Handler
public class PublishPostCommandHandler(IMongoRepository<BlogPost> repo)
    : IRequestHandler<PublishPostCommand, Result>
{
    public async Task<Result> Handle(PublishPostCommand request, CancellationToken ct)
    {
        var post = await repo.GetAsync(x => x.Id == request.PostId, ct);

        if (post is null)
            return Result.Fail(ResultType.NotFound, "Yazı bulunamadı.");

        if (post.Status == "Published")
            return Result.Fail(ResultType.Conflict, "Yazı zaten yayında.");

        post.Status = "Published";
        await repo.UpdateAsync(post, ct);

        return Result.Success(ResultType.Success, "Yazı yayınlandı.");
    }
}

// Query — sayfalı listeleme
public class GetPostsQueryHandler(IMongoRepository<BlogPost> repo)
    : IRequestHandler<GetPostsQuery, Result<PagedModel<BlogPostDto>>>
{
    public async Task<Result<PagedModel<BlogPostDto>>> Handle(
        GetPostsQuery request, CancellationToken ct)
    {
        var filterRequest = new MongoPagedFilterRequest<BlogPost>
        {
            FilterQuery = new PaginationFilterQuery
            {
                PageNumber = request.Page,
                PageSize = request.PageSize
            },
            Predicate = x => x.Status == "Published",
            OrderBy = q => q.OrderByDescending(x => x.CreatedDate)
        };

        var paged = await repo.GetAllPagedAsync(filterRequest, ct);

        var dto = new PagedModel<BlogPostDto>
        {
            TotalRecords = paged.TotalRecords,
            PagedData = paged.PagedData.Select(p => p.ToDto())
        };

        return Result<PagedModel<BlogPostDto>>.Success(ResultType.Success, dto);
    }
}

Mimari Notlar

  • ICurrentUserAccessor zorunludur: AddMongoRepository<T>() kayıt sırasında ICurrentUserAccessor DI'da bulunmalıdır. Yoksa runtime'da InvalidOperationException fırlatır.
  • Write metodlar SaveChanges çağırmaz: EF Core repository'sinden farklı olarak MongoDB repository'si her işlemi anında persist eder — ayrıca commit gerekmez.
  • ObjectId otomatik üretimi: MongoBaseEntityWithObjectId kullanan entity'lerde AddAsync() çağrısında Id default ise repository tarafından otomatik atanır.
  • Collection property'si: Aggregation pipeline, full-text search veya bulk write gibi sürücü seviyesinde operasyonlar için doğrudan IMongoCollection<T>'ye erişim sağlar.
  • LINQ → MongoDB query: Tüm Expression<Func<T, bool>> ifadeleri MongoDB .NET Driver'ın LINQ provider'ı aracılığıyla MongoDB query'sine çevrilir.

Lisans

Bu paket Ledbim Bilişim tarafından geliştirilmektedir. Ticari kullanım için lisans bilgisi için iletişime geçiniz.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 158 3/28/2026