EFGenericUnitOfWork 1.0.43

There is a newer version of this package available.
See the version list below for details.
dotnet add package EFGenericUnitOfWork --version 1.0.43
                    
NuGet\Install-Package EFGenericUnitOfWork -Version 1.0.43
                    
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="EFGenericUnitOfWork" Version="1.0.43" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EFGenericUnitOfWork" Version="1.0.43" />
                    
Directory.Packages.props
<PackageReference Include="EFGenericUnitOfWork" />
                    
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 EFGenericUnitOfWork --version 1.0.43
                    
#r "nuget: EFGenericUnitOfWork, 1.0.43"
                    
#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 EFGenericUnitOfWork@1.0.43
                    
#: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=EFGenericUnitOfWork&version=1.0.43
                    
Install as a Cake Addin
#tool nuget:?package=EFGenericUnitOfWork&version=1.0.43
                    
Install as a Cake Tool

EFGenericUnitOfWork

NuGet License: MIT

Author / Yazar: Mehmet SEYİTOĞLU
Company / Şirket: EMF BİLGİSAYAR YAZILIM YÖNETİM VE DANIŞMANLIK HİZMETLERİ
Target Framework: .NET 10
License / Lisans: MIT


🇹🇷 Türkçe Dokümantasyon

Genel Bakış

EFGenericUnitOfWork, Entity Framework Core üzerine inşa edilmiş, Repository Pattern, Unit of Work Pattern, SoftDelete ve Pagination desteği sunan genel amaçlı bir veri erişim kütüphanesidir.

Ne İşe Yarar?

  • ✅ Veritabanı işlemlerini soyutlayarak temiz mimari sağlar
  • ✅ Generic Repository ile CRUD işlemlerini tek merkezden yönetir
  • ✅ SoftDelete desteği ile kayıtları fiziksel silmeden işaretler
  • ✅ Sayfalama (Pagination) desteği sunar
  • ✅ Transaction yönetimi sağlar
  • ✅ SQL Function ve Stored Procedure desteği içerir
  • ✅ Bulk (toplu) işlemler için optimize metotlar sunar
  • ✅ Birden fazla veritabanı ile çalışma desteği (RepositoryOutDbName)
  • ✅ Hem senkron hem asenkron metotlar içerir

Kurulum

dotnet add package EFGenericUnitOfWork

DI Kaydı (Dependency Injection)

// Program.cs veya Startup.cs

// 1. Standart kullanım (tek veritabanı)
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddScoped<IUnitOfWork>(provider =>
    new UnitOfWork<AppDbContext>(provider.GetRequiredService<AppDbContext>()));

// 2. Dinamik veritabanı kullanımı (birden fazla veritabanı)
builder.Services.AddScoped<IDbContextFactory<AppDbContext>, AppDbContextFactory>();
builder.Services.AddScoped<IUnitOfWork>(provider =>
    new UnitOfWork<AppDbContext>(provider.GetRequiredService<IDbContextFactory<AppDbContext>>()));

Temel Kullanım Örnekleri

Repository ile CRUD İşlemleri
public class ProductService
{
    private readonly IUnitOfWork _unitOfWork;

    public ProductService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    // Tüm ürünleri getir
    public async Task<IEnumerable<Product>> GetAllProductsAsync()
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        return await repo.GetAllAsync();
    }

    // Filtreleme, sıralama ve include ile getir
    public async Task<IEnumerable<Product>> GetActiveProductsAsync()
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        return await repo.GetAllAsync(
            predicate: p => p.Price > 100,
            orderBy: q => q.OrderByDescending(p => p.CreatedDate),
            include: q => q.Include(p => p.Category),
            asNoTracking: true
        );
    }

    // ID ile getir
    public async Task<Product> GetProductByIdAsync(int id)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        return await repo.GetByIdAsync(id, includes: p => p.Category);
    }

    // Yeni ürün ekle
    public async Task AddProductAsync(Product product)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        await repo.AddAsync(product);
        await _unitOfWork.SaveChangesAsync();
    }

    // Ürün güncelle
    public async Task UpdateProductAsync(Product product)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        repo.Update(product);
        await _unitOfWork.SaveChangesAsync();
    }

    // Yumuşak silme (SoftDelete)
    public async Task SoftDeleteProductAsync(Product product)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        repo.Delete(product); // IsDeleted = true olarak işaretler
        await _unitOfWork.SaveChangesAsync();
    }

    // Kalıcı silme (Hard Delete)
    public async Task HardDeleteProductAsync(Product product)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        repo.Delete(product, hardDelete: true);
        await _unitOfWork.SaveChangesAsync();
    }
}
SoftDelete Kullanımı

Entity sınıfınızda IsDeleted property'si olmalıdır:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public bool IsDeleted { get; set; } // SoftDelete için gerekli

    // Özel property adı kullanılabilir:
    // public bool Silindi { get; set; }
}
// Varsayılan "IsDeleted" property ile
repo.Delete(product); // SoftDelete

// Özel property adı ile
repo.Delete(product, isDeletedPropertyName: "Silindi");

// Silinmiş kayıtlar dahil listeleme
var allProducts = await repo.GetAllAsync(softDeletedIncluded: true);
Sayfalama (Pagination)
// LINQ tabanlı sayfalama
var pagedProducts = await repo.GetPaginationListAsync(
    predicate: p => p.Price > 50,
    orderBy: q => q.OrderByDescending(p => p.Name),
    include: q => q.Include(p => p.Category),
    index: 0,    // Sayfa numarası (0 tabanlı)
    size: 10     // Sayfa boyutu
);

// Sonuçları kullanma
int totalCount = pagedProducts.Count;     // Toplam kayıt sayısı
int totalPages = pagedProducts.Pages;     // Toplam sayfa sayısı
bool hasNext = pagedProducts.HasNext;     // Sonraki sayfa var mı?
bool hasPrev = pagedProducts.HasPrevious; // Önceki sayfa var mı?
var items = pagedProducts.Items;          // Mevcut sayfadaki kayıtlar
SQL Function ve Stored Procedure
// SQL Function ile veri çekme (pagination ile)
var result = await repo.GetPaginationListFromFunctionAsync(
    functionName: "fn_GetActiveProducts",
    parameters: new { CategoryId = 5 },
    index: 0,
    size: 10
);

// SQL Function ile tüm verileri çekme (pagination olmadan)
var allData = await repo.GetAllFromFunctionAsync(
    functionName: "fn_GetActiveProducts",
    parameters: new { CategoryId = 5 }
);

// SQL Function + Where koşulu
var filtered = await repo.GetAllFromFunctionWithWhereAsync(
    functionName: "fn_GetProducts",
    functionParameters: new { Year = 2025 },
    predicate: p => p.Price > 100,
    orderBy: q => q.OrderByDescending(p => p.Name)
);

// Stored Procedure ile veri çekme
var spResult = await repo.GetAllFromStoredProcedureAsync(
    storedProcedureName: "sp_GetProductsByCategory",
    parameters: new { CategoryId = 5 }
);

// Raw SQL çalıştırma
var sqlResult = await repo.QuerySqlAsync(
    "SELECT * FROM Products WHERE Price > @p0", 100
);

// Scalar değer döndürme
var count = await repo.ExecuteScalarAsync<int>(
    "SELECT COUNT(*) FROM Products WHERE IsDeleted = 0"
);
Transaction Yönetimi
_unitOfWork.BeginTransaction();

try
{
    var productRepo = _unitOfWork.GetRepository<Product, int>();
    var logRepo = _unitOfWork.GetRepository<AuditLog, int>();

    await productRepo.AddAsync(newProduct);
    await logRepo.AddAsync(new AuditLog { Action = "ProductAdded" });

    await _unitOfWork.CommitTransactionAsync();
}
catch
{
    await _unitOfWork.RollbackTransactionAsync();
    throw;
}
Aggregate Metotları
var repo = _unitOfWork.GetRepository<Product, int>();

// Sayma
int count = await repo.CountAsync(p => p.Price > 100);

// Toplam
decimal total = await repo.SumAsync(p => p.Price, predicate: p => p.IsActive);

// Ortalama
decimal avg = await repo.AverageAsync(p => p.Price);

// Minimum / Maximum
decimal min = await repo.MinAsync(p => p.Price, predicate: p => p.CategoryId == 1);
decimal max = await repo.MaxAsync(p => p.Price);

// Varlık kontrolü
bool exists = await repo.ExistsAsync(p => p.Name == "Test");
Bulk İşlemler
var repo = _unitOfWork.GetRepository<Product, int>();

// Toplu ekleme
await repo.BulkInsertAsync(productList);

// Toplu güncelleme
await repo.BulkUpdateAsync(productList);

// Toplu silme (soft delete)
await repo.BulkDeleteAsync(productList);

// Toplu silme (hard delete)
await repo.BulkDeleteAsync(productList, hardDelete: true);
Dinamik Veritabanı Değiştirme
// Context'i farklı bir veritabanı ile başlat
_unitOfWork.InitializeContext("SecondDatabase");

var repo = _unitOfWork.GetRepositoryOutDbName<Product, int>();
var products = await repo.GetAllAsync();

🇬🇧 English Documentation

Overview

EFGenericUnitOfWork is a general-purpose data access library built on top of Entity Framework Core, providing Repository Pattern, Unit of Work Pattern, SoftDelete, and Pagination support.

What Does It Do?

  • ✅ Abstracts database operations for clean architecture
  • ✅ Centralized CRUD operations via Generic Repository
  • ✅ SoftDelete support — marks records instead of physical deletion
  • ✅ Built-in Pagination support
  • ✅ Transaction management
  • ✅ SQL Function and Stored Procedure support
  • ✅ Optimized Bulk operations
  • ✅ Multi-database support (RepositoryOutDbName)
  • ✅ Both synchronous and asynchronous methods

Installation

dotnet add package EFGenericUnitOfWork

DI Registration (Dependency Injection)

// Program.cs or Startup.cs

// 1. Standard usage (single database)
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddScoped<IUnitOfWork>(provider =>
    new UnitOfWork<AppDbContext>(provider.GetRequiredService<AppDbContext>()));

// 2. Dynamic database usage (multiple databases)
builder.Services.AddScoped<IDbContextFactory<AppDbContext>, AppDbContextFactory>();
builder.Services.AddScoped<IUnitOfWork>(provider =>
    new UnitOfWork<AppDbContext>(provider.GetRequiredService<IDbContextFactory<AppDbContext>>()));

Basic Usage Examples

CRUD Operations with Repository
public class ProductService
{
    private readonly IUnitOfWork _unitOfWork;

    public ProductService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    // Get all products
    public async Task<IEnumerable<Product>> GetAllProductsAsync()
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        return await repo.GetAllAsync();
    }

    // Get with filtering, sorting and includes
    public async Task<IEnumerable<Product>> GetActiveProductsAsync()
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        return await repo.GetAllAsync(
            predicate: p => p.Price > 100,
            orderBy: q => q.OrderByDescending(p => p.CreatedDate),
            include: q => q.Include(p => p.Category),
            asNoTracking: true
        );
    }

    // Get by ID
    public async Task<Product> GetProductByIdAsync(int id)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        return await repo.GetByIdAsync(id, includes: p => p.Category);
    }

    // Add new product
    public async Task AddProductAsync(Product product)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        await repo.AddAsync(product);
        await _unitOfWork.SaveChangesAsync();
    }

    // Update product
    public async Task UpdateProductAsync(Product product)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        repo.Update(product);
        await _unitOfWork.SaveChangesAsync();
    }

    // Soft Delete
    public async Task SoftDeleteProductAsync(Product product)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        repo.Delete(product); // Sets IsDeleted = true
        await _unitOfWork.SaveChangesAsync();
    }

    // Hard Delete
    public async Task HardDeleteProductAsync(Product product)
    {
        var repo = _unitOfWork.GetRepository<Product, int>();
        repo.Delete(product, hardDelete: true);
        await _unitOfWork.SaveChangesAsync();
    }
}
SoftDelete Usage

Your entity class must have an IsDeleted property:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public bool IsDeleted { get; set; } // Required for SoftDelete

    // Custom property name is also supported:
    // public bool Deleted { get; set; }
}
// Default "IsDeleted" property
repo.Delete(product); // SoftDelete

// Custom property name
repo.Delete(product, isDeletedPropertyName: "Deleted");

// Include soft-deleted records in listing
var allProducts = await repo.GetAllAsync(softDeletedIncluded: true);
Pagination
// LINQ-based pagination
var pagedProducts = await repo.GetPaginationListAsync(
    predicate: p => p.Price > 50,
    orderBy: q => q.OrderByDescending(p => p.Name),
    include: q => q.Include(p => p.Category),
    index: 0,    // Page number (0-based)
    size: 10     // Page size
);

// Using results
int totalCount = pagedProducts.Count;     // Total record count
int totalPages = pagedProducts.Pages;     // Total page count
bool hasNext = pagedProducts.HasNext;     // Has next page?
bool hasPrev = pagedProducts.HasPrevious; // Has previous page?
var items = pagedProducts.Items;          // Items on current page
SQL Functions and Stored Procedures
// SQL Function with pagination
var result = await repo.GetPaginationListFromFunctionAsync(
    functionName: "fn_GetActiveProducts",
    parameters: new { CategoryId = 5 },
    index: 0,
    size: 10
);

// SQL Function without pagination
var allData = await repo.GetAllFromFunctionAsync(
    functionName: "fn_GetActiveProducts",
    parameters: new { CategoryId = 5 }
);

// SQL Function + Where clause
var filtered = await repo.GetAllFromFunctionWithWhereAsync(
    functionName: "fn_GetProducts",
    functionParameters: new { Year = 2025 },
    predicate: p => p.Price > 100,
    orderBy: q => q.OrderByDescending(p => p.Name)
);

// Stored Procedure
var spResult = await repo.GetAllFromStoredProcedureAsync(
    storedProcedureName: "sp_GetProductsByCategory",
    parameters: new { CategoryId = 5 }
);

// Raw SQL execution
var sqlResult = await repo.QuerySqlAsync(
    "SELECT * FROM Products WHERE Price > @p0", 100
);

// Scalar value
var count = await repo.ExecuteScalarAsync<int>(
    "SELECT COUNT(*) FROM Products WHERE IsDeleted = 0"
);
Transaction Management
_unitOfWork.BeginTransaction();

try
{
    var productRepo = _unitOfWork.GetRepository<Product, int>();
    var logRepo = _unitOfWork.GetRepository<AuditLog, int>();

    await productRepo.AddAsync(newProduct);
    await logRepo.AddAsync(new AuditLog { Action = "ProductAdded" });

    await _unitOfWork.CommitTransactionAsync();
}
catch
{
    await _unitOfWork.RollbackTransactionAsync();
    throw;
}
Aggregate Methods
var repo = _unitOfWork.GetRepository<Product, int>();

// Count
int count = await repo.CountAsync(p => p.Price > 100);

// Sum
decimal total = await repo.SumAsync(p => p.Price, predicate: p => p.IsActive);

// Average
decimal avg = await repo.AverageAsync(p => p.Price);

// Min / Max
decimal min = await repo.MinAsync(p => p.Price, predicate: p => p.CategoryId == 1);
decimal max = await repo.MaxAsync(p => p.Price);

// Exists
bool exists = await repo.ExistsAsync(p => p.Name == "Test");
Bulk Operations
var repo = _unitOfWork.GetRepository<Product, int>();

// Bulk insert
await repo.BulkInsertAsync(productList);

// Bulk update
await repo.BulkUpdateAsync(productList);

// Bulk soft delete
await repo.BulkDeleteAsync(productList);

// Bulk hard delete
await repo.BulkDeleteAsync(productList, hardDelete: true);
Dynamic Database Switching
// Initialize context with a different database
_unitOfWork.InitializeContext("SecondDatabase");

var repo = _unitOfWork.GetRepositoryOutDbName<Product, int>();
var products = await repo.GetAllAsync();

API Reference / API Referansı

Interface Description (EN) Açıklama (TR)
IRepository<T, TId> Generic repository with CRUD, pagination, aggregation CRUD, sayfalama, toplama metotları içeren genel repository
IRepositoryOutDbName<T, TId> Repository with dynamic database switching Dinamik veritabanı değiştirme destekli repository
IUnitOfWork Unit of Work with transaction support Transaction destekli Unit of Work
IDbContextFactory<TContext> Factory for creating DbContext with database name Veritabanı adı ile DbContext oluşturma fabrikası
IPaginate<T> Pagination result model Sayfalama sonuç modeli
PageRequest Pagination request model Sayfalama istek modeli

Dependencies / Bağımlılıklar

  • Microsoft.EntityFrameworkCore.Abstractions (10.0.5)
  • Microsoft.EntityFrameworkCore.Design (10.0.5)
  • Microsoft.EntityFrameworkCore.SqlServer (10.0.5)
  • Microsoft.EntityFrameworkCore.Tools (10.0.5)
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 (1)

Showing the top 1 NuGet packages that depend on EFGenericUnitOfWork:

Package Downloads
EmfGlobalCaching

A global caching library with support for MediatR, Memory Caching, and Redis Caching, enhancing performance and scalability.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.44 106 4/27/2026
1.0.43 101 4/20/2026
1.0.42 126 3/16/2026
1.0.41 217 7/27/2025
1.0.40 197 7/27/2025
1.0.39 197 7/27/2025
1.0.38 208 7/26/2025
1.0.37 230 7/26/2025
1.0.36 245 7/26/2025
1.0.35 284 7/26/2025
1.0.34 295 7/26/2025
1.0.33 290 7/26/2025
1.0.32 469 3/24/2025
1.0.31 343 3/23/2025
1.0.30 257 3/11/2025
1.0.29 252 3/11/2025
1.0.28 297 3/5/2025
1.0.27 192 2/18/2025
1.0.26 183 2/18/2025
1.0.25 188 2/17/2025
Loading failed

Initial release with support for Entity Framework Core, Repository Pattern, UnitOfWork Pattern, SoftDelete functionality, paging, and synchronous/asynchronous support.