{"id":29195896,"url":"https://github.com/furkansarikaya/fs.entityframework.library","last_synced_at":"2026-04-01T20:54:49.504Z","repository":{"id":301048835,"uuid":"1007991092","full_name":"furkansarikaya/FS.EntityFramework.Library","owner":"furkansarikaya","description":"A comprehensive, production-ready Entity Framework Core library for .NET 9+ providing Repository pattern, Unit of Work, Specification pattern, Domain Events, Fluent Configuration API, automatic audit tracking, soft delete \u0026 restore, dynamic filtering, pagination, and modular ID generation (GUID V7, ULID) with zero-configuration setup.","archived":false,"fork":false,"pushed_at":"2025-08-03T21:54:00.000Z","size":258,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-27T05:31:36.202Z","etag":null,"topics":["audit-tracking","clean-architecture","csharp","domain-events","dotnet","dynamic-filtering","entity-framework-core","extensible","fluent-api","guid-v7","id-generation","nuget-package","pagination","production-ready","repository-pattern","soft-delete","specification-pattern","ulid","unit-of-work","zero-configuration"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/FS.EntityFramework.Library","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/furkansarikaya.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-24T21:16:50.000Z","updated_at":"2025-08-03T21:54:03.000Z","dependencies_parsed_at":"2025-06-24T22:52:53.107Z","dependency_job_id":"59ff7bc7-9c7e-405a-b2af-201913e3f128","html_url":"https://github.com/furkansarikaya/FS.EntityFramework.Library","commit_stats":null,"previous_names":["furkansarikaya/fs.entityframework.library"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/furkansarikaya/FS.EntityFramework.Library","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/furkansarikaya%2FFS.EntityFramework.Library","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/furkansarikaya%2FFS.EntityFramework.Library/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/furkansarikaya%2FFS.EntityFramework.Library/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/furkansarikaya%2FFS.EntityFramework.Library/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/furkansarikaya","download_url":"https://codeload.github.com/furkansarikaya/FS.EntityFramework.Library/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/furkansarikaya%2FFS.EntityFramework.Library/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274433837,"owners_count":25284427,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-10T02:00:12.551Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audit-tracking","clean-architecture","csharp","domain-events","dotnet","dynamic-filtering","entity-framework-core","extensible","fluent-api","guid-v7","id-generation","nuget-package","pagination","production-ready","repository-pattern","soft-delete","specification-pattern","ulid","unit-of-work","zero-configuration"],"created_at":"2025-07-02T05:06:46.691Z","updated_at":"2026-03-27T03:17:57.439Z","avatar_url":"https://github.com/furkansarikaya.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FS.EntityFramework.Library\n\n[![NuGet Version](https://img.shields.io/nuget/v/FS.EntityFramework.Library.svg)](https://www.nuget.org/packages/FS.EntityFramework.Library/)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/FS.EntityFramework.Library.svg)](https://www.nuget.org/packages/FS.EntityFramework.Library/)\n[![GitHub License](https://img.shields.io/github/license/furkansarikaya/FS.EntityFramework.Library)](https://github.com/furkansarikaya/FS.EntityFramework.Library/blob/main/LICENSE)\n[![GitHub Stars](https://img.shields.io/github/stars/furkansarikaya/FS.EntityFramework.Library.svg)](https://github.com/furkansarikaya/FS.EntityFramework.Library/stargazers)\n\nA comprehensive, production-ready Entity Framework Core library providing **Repository pattern**, **Unit of Work**, **Specification pattern**, **dynamic filtering**, **pagination support**, **Domain Events**, **Domain-Driven Design (DDD)**, **Fluent Configuration API**, and **modular ID generation** strategies for .NET applications.\n\n## 🌟 Why Choose FS.EntityFramework.Library?\n\nThis library transforms Entity Framework Core into a powerful, enterprise-ready data access layer that follows best practices and design patterns. Whether you're building a simple application or a complex domain-rich system, this library provides the tools you need to create maintainable, testable, and scalable data access code.\n\n## 📋 Table of Contents\n\n- [🚀 Quick Start](#-quick-start)\n- [💾 Installation](#-installation)\n- [🏗️ Step-by-Step Implementation Guide](#️-step-by-step-implementation-guide)\n- [🏛️ Domain-Driven Design Features](#️-domain-driven-design-features)\n- [📊 Advanced Features](#-advanced-features)\n- [🎯 Best Practices](#-best-practices)\n- [🔧 Troubleshooting](#-troubleshooting)\n- [🤝 Contributing](#-contributing)\n\n## 🚀 Quick Start\n\nGet started with FS.EntityFramework.Library in just 5 steps:\n\n### Step 1: Install the Package\n\n```bash\ndotnet add package FS.EntityFramework.Library\n```\n\n### Step 2: Configure Your DbContext\n\n```csharp\npublic class ApplicationDbContext : DbContext\n{\n    public ApplicationDbContext(DbContextOptions\u003cApplicationDbContext\u003e options) : base(options) { }\n    \n    public DbSet\u003cProduct\u003e Products { get; set; }\n    public DbSet\u003cCategory\u003e Categories { get; set; }\n}\n```\n\n### Step 3: Configure Services\n\n```csharp\n// In Program.cs or Startup.cs\nservices.AddDbContext\u003cApplicationDbContext\u003e(options =\u003e\n    options.UseSqlServer(connectionString));\n\n// Add FS.EntityFramework services\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .Build();\n```\n\n### Step 4: Create Your First Entity\n\n```csharp\npublic class Product : BaseAuditableEntity\u003cint\u003e\n{\n    public string Name { get; set; } = string.Empty;\n    public decimal Price { get; set; }\n    public string Description { get; set; } = string.Empty;\n}\n```\n\n### Step 5: Use in Your Services\n\n```csharp\npublic class ProductService\n{\n    private readonly IUnitOfWork _unitOfWork;\n    \n    public ProductService(IUnitOfWork unitOfWork)\n    {\n        _unitOfWork = unitOfWork;\n    }\n    \n    public async Task\u003cProduct\u003e CreateProductAsync(string name, decimal price)\n    {\n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n        var product = new Product { Name = name, Price = price };\n        \n        await repository.AddAsync(product);\n        await _unitOfWork.SaveChangesAsync();\n        \n        return product;\n    }\n}\n```\n\n## 💾 Installation\n\n### Core Package\n\n```bash\n# Core library with all essential features including DDD\ndotnet add package FS.EntityFramework.Library\n```\n\n### Extension Packages (Optional)\n\n```bash\n# GUID Version 7 ID generation (.NET 10+)\ndotnet add package FS.EntityFramework.Library.GuidV7\n\n# ULID ID generation\ndotnet add package FS.EntityFramework.Library.UlidGenerator\n```\n\n### Requirements\n\n- **.NET 10.0** or later\n- **Entity Framework Core 10.0.3** or later\n- **Microsoft.AspNetCore.Http.Abstractions 2.3.0** or later (for HttpContext support)\n\n## 🏗️ Step-by-Step Implementation Guide\n\nLet's build a complete example from scratch, implementing all the major features of the library.\n\n### Step 1: Set Up Your Project Structure\n\nFirst, create a new project and organize it following clean architecture principles:\n\n```\nYourProject/\n├── Models/           # Entity models\n├── Services/         # Business logic\n├── Repositories/     # Custom repositories (if needed)\n└── Configuration/    # Database configuration\n```\n\n### Step 2: Install Required Packages\n\n```bash\ndotnet new webapi -n YourProject\ncd YourProject\ndotnet add package FS.EntityFramework.Library\ndotnet add package Microsoft.EntityFrameworkCore.SqlServer\n```\n\n### Step 3: Create Base Entities\n\nUnderstanding the entity hierarchy is crucial. The library provides several base entity classes:\n\n```csharp\n// Models/Category.cs\nusing FS.EntityFramework.Library.Common;\n\n/// \u003csummary\u003e\n/// Simple entity with just ID and domain events support\n/// \u003c/summary\u003e\npublic class Category : BaseEntity\u003cint\u003e\n{\n    public string Name { get; set; } = string.Empty;\n    public string Description { get; set; } = string.Empty;\n    \n    // Navigation property\n    public virtual ICollection\u003cProduct\u003e Products { get; set; } = new List\u003cProduct\u003e();\n}\n\n// Models/Product.cs\nusing FS.EntityFramework.Library.Common;\n\n/// \u003csummary\u003e\n/// Auditable entity with creation and modification tracking\n/// \u003c/summary\u003e\npublic class Product : BaseAuditableEntity\u003cint\u003e, ISoftDelete\n{\n    public string Name { get; set; } = string.Empty;\n    public decimal Price { get; set; }\n    public string Description { get; set; } = string.Empty;\n    public int CategoryId { get; set; }\n    \n    // Navigation property\n    public virtual Category Category { get; set; } = null!;\n    \n    // ISoftDelete properties (automatically implemented)\n    public bool IsDeleted { get; set; }\n    public DateTime? DeletedAt { get; set; }\n    public string? DeletedBy { get; set; }\n    \n    // Business method with domain events\n    public void UpdatePrice(decimal newPrice)\n    {\n        if (newPrice \u003c= 0)\n            throw new ArgumentException(\"Price must be positive\", nameof(newPrice));\n            \n        var oldPrice = Price;\n        Price = newPrice;\n        \n        // Raise domain event\n        AddDomainEvent(new ProductPriceChangedEvent(Id, oldPrice, newPrice));\n    }\n}\n```\n\n### Step 4: Create Domain Events\n\nDomain events enable loose coupling between different parts of your application:\n\n```csharp\n// Models/Events/ProductPriceChangedEvent.cs\nusing FS.EntityFramework.Library.Common;\n\npublic class ProductPriceChangedEvent : DomainEvent\n{\n    public ProductPriceChangedEvent(int productId, decimal oldPrice, decimal newPrice)\n    {\n        ProductId = productId;\n        OldPrice = oldPrice;\n        NewPrice = newPrice;\n    }\n    \n    public int ProductId { get; }\n    public decimal OldPrice { get; }\n    public decimal NewPrice { get; }\n}\n\n// Services/EventHandlers/ProductPriceChangedEventHandler.cs\nusing FS.EntityFramework.Library.Events;\n\npublic class ProductPriceChangedEventHandler : IDomainEventHandler\u003cProductPriceChangedEvent\u003e\n{\n    private readonly ILogger\u003cProductPriceChangedEventHandler\u003e _logger;\n    \n    public ProductPriceChangedEventHandler(ILogger\u003cProductPriceChangedEventHandler\u003e logger)\n    {\n        _logger = logger;\n    }\n    \n    public async Task Handle(ProductPriceChangedEvent domainEvent, CancellationToken cancellationToken = default)\n    {\n        _logger.LogInformation(\"Product {ProductId} price changed from {OldPrice} to {NewPrice}\", \n            domainEvent.ProductId, domainEvent.OldPrice, domainEvent.NewPrice);\n        \n        // Add your business logic here:\n        // - Send price change notification emails\n        // - Update related data\n        // - Trigger other business processes\n        \n        await Task.CompletedTask;\n    }\n}\n```\n\n### Step 5: Configure Your DbContext\n\nYou have two options for DbContext configuration:\n\n#### Option A: Use FSDbContext (Recommended)\n\n```csharp\n// Data/ApplicationDbContext.cs\nusing FS.EntityFramework.Library.Common;\n\npublic class ApplicationDbContext : FSDbContext\n{\n    public ApplicationDbContext(DbContextOptions\u003cApplicationDbContext\u003e options, IServiceProvider serviceProvider) \n        : base(options, serviceProvider)\n    {\n        // FSDbContext automatically applies all FS.EntityFramework configurations\n    }\n    \n    public DbSet\u003cProduct\u003e Products { get; set; } = null!;\n    public DbSet\u003cCategory\u003e Categories { get; set; } = null!;\n    \n    protected override void OnModelCreating(ModelBuilder modelBuilder)\n    {\n        base.OnModelCreating(modelBuilder); // This applies FS configurations\n        \n        // Add your custom configurations here\n        modelBuilder.Entity\u003cProduct\u003e(entity =\u003e\n        {\n            entity.HasKey(e =\u003e e.Id);\n            entity.Property(e =\u003e e.Name).HasMaxLength(200).IsRequired();\n            entity.Property(e =\u003e e.Price).HasPrecision(18, 2);\n            \n            entity.HasOne(e =\u003e e.Category)\n                  .WithMany(c =\u003e c.Products)\n                  .HasForeignKey(e =\u003e e.CategoryId);\n        });\n        \n        modelBuilder.Entity\u003cCategory\u003e(entity =\u003e\n        {\n            entity.HasKey(e =\u003e e.Id);\n            entity.Property(e =\u003e e.Name).HasMaxLength(100).IsRequired();\n        });\n    }\n}\n```\n\n#### Option B: Use Regular DbContext with Manual Configuration\n\n```csharp\n// Data/ApplicationDbContext.cs\npublic class ApplicationDbContext : DbContext\n{\n    private readonly IServiceProvider? _serviceProvider;\n    \n    public ApplicationDbContext(DbContextOptions\u003cApplicationDbContext\u003e options, IServiceProvider serviceProvider) \n        : base(options)\n    {\n        _serviceProvider = serviceProvider;\n    }\n    \n    public DbSet\u003cProduct\u003e Products { get; set; } = null!;\n    public DbSet\u003cCategory\u003e Categories { get; set; } = null!;\n    \n    protected override void OnModelCreating(ModelBuilder modelBuilder)\n    {\n        base.OnModelCreating(modelBuilder);\n        \n        // Apply FS.EntityFramework configurations manually\n        if (_serviceProvider != null)\n        {\n            modelBuilder.ApplyFSEntityFrameworkConfigurations(_serviceProvider);\n        }\n        \n        // Your entity configurations...\n    }\n}\n```\n\n### Step 6: Configure Services with Fluent API\n\nThe Fluent Configuration API provides a clean way to configure all features:\n\n```csharp\n// Program.cs\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add DbContext\nbuilder.Services.AddDbContext\u003cApplicationDbContext\u003e(options =\u003e\n    options.UseSqlServer(builder.Configuration.GetConnectionString(\"DefaultConnection\")));\n\n// Configure FS.EntityFramework with all features\nbuilder.Services.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    // Enable audit tracking\n    .WithAudit()\n        .UsingHttpContext() // For web applications\n    \n    // Enable domain events\n    .WithDomainEvents()\n        .UsingDefaultDispatcher()\n        .WithAutoHandlerDiscovery() // Automatically find event handlers\n    .Complete()\n    \n    // Enable soft delete\n    .WithSoftDelete()\n    \n    // Build the configuration\n    .Build();\n\nvar app = builder.Build();\n```\n\n### Step 7: Create Business Services\n\nNow create services that use the repository pattern:\n\n```csharp\n// Services/ProductService.cs\npublic class ProductService\n{\n    private readonly IUnitOfWork _unitOfWork;\n    private readonly ILogger\u003cProductService\u003e _logger;\n    \n    public ProductService(IUnitOfWork unitOfWork, ILogger\u003cProductService\u003e logger)\n    {\n        _unitOfWork = unitOfWork;\n        _logger = logger;\n    }\n    \n    public async Task\u003cProduct\u003e CreateProductAsync(CreateProductRequest request)\n    {\n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n        \n        var product = new Product\n        {\n            Name = request.Name,\n            Price = request.Price,\n            Description = request.Description,\n            CategoryId = request.CategoryId\n        };\n        \n        await repository.AddAsync(product);\n        await _unitOfWork.SaveChangesAsync();\n        \n        _logger.LogInformation(\"Created product: {ProductName}\", product.Name);\n        return product;\n    }\n    \n    public async Task\u003cProduct?\u003e GetProductByIdAsync(int id)\n    {\n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n        return await repository.GetByIdAsync(id);\n    }\n    \n    public async Task\u003cIPaginate\u003cProduct\u003e\u003e GetProductsPagedAsync(int page, int size)\n    {\n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n        \n        return await repository.GetPagedAsync(\n            pageIndex: page,\n            pageSize: size,\n            includes: new List\u003cExpression\u003cFunc\u003cProduct, object\u003e\u003e\u003e { p =\u003e p.Category },\n            orderBy: query =\u003e query.OrderBy(p =\u003e p.Name)\n        );\n    }\n    \n    public async Task UpdateProductPriceAsync(int id, decimal newPrice)\n    {\n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n        var product = await repository.GetByIdAsync(id);\n        \n        if (product == null)\n            throw new InvalidOperationException($\"Product with ID {id} not found\");\n        \n        product.UpdatePrice(newPrice); // This will raise a domain event\n        \n        await repository.UpdateAsync(product);\n        await _unitOfWork.SaveChangesAsync(); // Domain events will be dispatched here\n    }\n    \n    public async Task SoftDeleteProductAsync(int id)\n    {\n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n        var product = await repository.GetByIdAsync(id);\n        \n        if (product != null)\n        {\n            await repository.DeleteAsync(product); // Soft delete\n            await _unitOfWork.SaveChangesAsync();\n        }\n    }\n    \n    public async Task RestoreProductAsync(int id)\n    {\n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n        await repository.RestoreAsync(id); // Restore soft deleted product\n        await _unitOfWork.SaveChangesAsync();\n    }\n}\n\n// DTOs for service methods\npublic record CreateProductRequest(string Name, decimal Price, string Description, int CategoryId);\n```\n\n### Step 8: Implement Dynamic Filtering\n\nThe library provides a comprehensive, type-safe dynamic filtering system with fluent API, OR/AND groups, sorting, convenience methods, and reusable scopes.\n\n#### Strongly-Typed FilterBuilder\\\u003cT\\\u003e (Recommended)\n\nThe generic `FilterBuilder\u003cT\u003e` provides compile-time validated field names, IntelliSense, and automatic value conversion:\n\n```csharp\nusing FS.EntityFramework.Library.Models;\n\npublic class ProductSearchService\n{\n    private readonly IUnitOfWork _unitOfWork;\n\n    public ProductSearchService(IUnitOfWork unitOfWork)\n    {\n        _unitOfWork = unitOfWork;\n    }\n\n    public async Task\u003cIPaginate\u003cProduct\u003e\u003e SearchProductsAsync(ProductFilterRequest request)\n    {\n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n\n        // Fully type-safe: field names, operators, and values validated at compile-time\n        var filter = FilterBuilder\u003cProduct\u003e.Create()\n            .Search(request.SearchTerm)\n            .WhereIf(request.MinPrice.HasValue, p =\u003e p.Price,\n                     FilterOperator.GreaterThanOrEqual, request.MinPrice)\n            .WhereIf(request.MaxPrice.HasValue, p =\u003e p.Price,\n                     FilterOperator.LessThanOrEqual, request.MaxPrice)\n            .WhereIf(request.CategoryId.HasValue, p =\u003e p.CategoryId,\n                     FilterOperator.Equals, request.CategoryId)\n            .WhereIsNull(p =\u003e p.DeletedAt)\n            .OrderByDescending(p =\u003e p.CreatedAt)\n            .OrderBy(p =\u003e p.Name)\n            .Build();\n\n        // Sorting is built into the filter model — no separate orderBy needed\n        return await repository.GetPagedWithFilterAsync(\n            filter,\n            request.Page,\n            request.PageSize,\n            includes: new List\u003cExpression\u003cFunc\u003cProduct, object\u003e\u003e\u003e { p =\u003e p.Category }\n        );\n    }\n}\n\npublic record ProductFilterRequest(\n    string? SearchTerm = null,\n    decimal? MinPrice = null,\n    decimal? MaxPrice = null,\n    int? CategoryId = null,\n    int Page = 1,\n    int PageSize = 10);\n```\n\n#### Convenience Methods: WhereBetween \u0026 WhereDateRange\n\n```csharp\n// Price range in a single call (adds \u003e= and \u003c= filters)\nvar filter = FilterBuilder\u003cProduct\u003e.Create()\n    .WhereBetween(p =\u003e p.Price, 100m, 999m)\n    .WhereDateRange(p =\u003e p.CreatedAt, DateTime.Today.AddDays(-30), DateTime.Today)\n    .Build();\n```\n\n#### OR / AND Groups\n\nBuild complex logical expressions with grouped filters:\n\n```csharp\nvar filter = FilterBuilder\u003cProduct\u003e.Create()\n    .WhereEquals(p =\u003e p.IsActive, true)\n    .OrGroup(g =\u003e g                                    // AND (\n        .WhereGreaterThan(p =\u003e p.Price, 1000m)         //   Price \u003e 1000\n        .WhereEquals(p =\u003e p.IsFeatured, true))         //   OR IsFeatured = true )\n    .Build();\n// SQL: WHERE IsActive = 1 AND (Price \u003e 1000 OR IsFeatured = 1)\n```\n\n#### Set Operators: WhereIn \u0026 WhereNotIn\n\n```csharp\nvar filter = FilterBuilder\u003cProduct\u003e.Create()\n    .WhereIn(p =\u003e p.Status, 1, 2, 3)                  // WHERE Status IN (1, 2, 3)\n    .WhereNotIn(p =\u003e p.CategoryId, 5, 10)              // AND CategoryId NOT IN (5, 10)\n    .Build();\n```\n\n#### Reusable Filter Scopes\n\nExtract common filter combinations into reusable scopes:\n\n```csharp\n// Define a reusable scope\npublic class ActiveProductScope : IFilterScope\u003cProduct\u003e\n{\n    public void Apply(FilterBuilder\u003cProduct\u003e builder)\n    {\n        builder\n            .WhereEquals(p =\u003e p.IsActive, true)\n            .WhereIsNull(p =\u003e p.DeletedAt);\n    }\n}\n\n// Apply across different queries\nvar filter = FilterBuilder\u003cProduct\u003e.Create()\n    .ApplyScope(new ActiveProductScope())\n    .WhereBetween(p =\u003e p.Price, 50m, 500m)\n    .OrderBy(p =\u003e p.Name)\n    .Build();\n```\n\n#### Dynamic Sorting via FilterModel\n\nSorting can be defined in the filter model and is automatically applied by the repository:\n\n```csharp\nvar filter = FilterBuilder\u003cProduct\u003e.Create()\n    .WhereGreaterThan(p =\u003e p.Price, 100m)\n    .OrderByDescending(p =\u003e p.CreatedAt)    // Primary sort\n    .OrderBy(p =\u003e p.Name)                   // ThenBy\n    .Build();\n\n// No orderBy parameter needed — sorts are applied from FilterModel.Sorts\nvar result = await repository.GetPagedWithFilterAsync(filter, pageIndex: 0, pageSize: 20);\n\n// Explicit orderBy parameter still takes precedence when provided\n```\n\n#### String-Based FilterBuilder (API/JSON Scenarios)\n\nThe non-generic `FilterBuilder` is available for scenarios where the entity type isn't known at compile time (e.g., API controllers receiving filter JSON):\n\n```csharp\nvar filter = FilterBuilder.Create()\n    .Search(\"laptop\")\n    .WhereGreaterThanOrEqual(nameof(Product.Price), \"500\")\n    .WhereBetween(nameof(Product.Price), \"100\", \"999\")\n    .OrGroup(g =\u003e g\n        .WhereEquals(\"CategoryId\", \"1\")\n        .WhereEquals(\"CategoryId\", \"2\"))\n    .OrderByDescending(nameof(Product.CreatedAt))\n    .Build();\n```\n\n#### Direct FilterItem Constructor\n\n```csharp\nvar filter = new FilterModel\n{\n    SearchTerm = \"laptop\",\n    Filters = new List\u003cFilterItem\u003e\n    {\n        new(nameof(Product.Price), FilterOperator.GreaterThanOrEqual, \"500\"),\n        new(nameof(Product.CategoryId), FilterOperator.Equals, \"1\"),\n        new(nameof(Product.Status), FilterOperator.In, \"1,2,3\"),\n        new(nameof(Product.DeletedAt), FilterOperator.IsNull)\n    }\n};\n```\n\n#### Backward-Compatible String Syntax\n\nThe original string-based API still works and now supports short aliases:\n\n```csharp\n// All of these are equivalent:\nnew FilterItem { Field = \"Price\", Operator = \"greaterthanorequal\", Value = \"500\" }\nnew FilterItem { Field = \"Price\", Operator = \"gte\", Value = \"500\" }\nnew FilterItem(\"Price\", FilterOperator.GreaterThanOrEqual, \"500\")\n```\n\n### Step 9: Create API Controllers\n\nFinally, create controllers that expose your services:\n\n```csharp\n// Controllers/ProductsController.cs\n[ApiController]\n[Route(\"api/[controller]\")]\npublic class ProductsController : ControllerBase\n{\n    private readonly ProductService _productService;\n    private readonly ProductSearchService _searchService;\n    \n    public ProductsController(ProductService productService, ProductSearchService searchService)\n    {\n        _productService = productService;\n        _searchService = searchService;\n    }\n    \n    [HttpPost]\n    public async Task\u003cActionResult\u003cProduct\u003e\u003e CreateProduct(CreateProductRequest request)\n    {\n        var product = await _productService.CreateProductAsync(request);\n        return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product);\n    }\n    \n    [HttpGet(\"{id}\")]\n    public async Task\u003cActionResult\u003cProduct\u003e\u003e GetProduct(int id)\n    {\n        var product = await _productService.GetProductByIdAsync(id);\n        return product == null ? NotFound() : Ok(product);\n    }\n    \n    [HttpGet]\n    public async Task\u003cActionResult\u003cIPaginate\u003cProduct\u003e\u003e\u003e GetProducts(int page = 1, int size = 10)\n    {\n        var products = await _productService.GetProductsPagedAsync(page, size);\n        return Ok(products);\n    }\n    \n    [HttpGet(\"search\")]\n    public async Task\u003cActionResult\u003cIPaginate\u003cProduct\u003e\u003e\u003e SearchProducts([FromQuery] ProductFilterRequest request)\n    {\n        var products = await _searchService.SearchProductsAsync(request);\n        return Ok(products);\n    }\n    \n    [HttpPut(\"{id}/price\")]\n    public async Task\u003cIActionResult\u003e UpdateProductPrice(int id, [FromBody] decimal newPrice)\n    {\n        await _productService.UpdateProductPriceAsync(id, newPrice);\n        return NoContent();\n    }\n    \n    [HttpDelete(\"{id}\")]\n    public async Task\u003cIActionResult\u003e DeleteProduct(int id)\n    {\n        await _productService.SoftDeleteProductAsync(id);\n        return NoContent();\n    }\n    \n    [HttpPost(\"{id}/restore\")]\n    public async Task\u003cIActionResult\u003e RestoreProduct(int id)\n    {\n        await _productService.RestoreProductAsync(id);\n        return NoContent();\n    }\n}\n```\n\n### Step 10: Register Services\n\nDon't forget to register your custom services:\n\n```csharp\n// Program.cs (continued)\nbuilder.Services.AddScoped\u003cProductService\u003e();\nbuilder.Services.AddScoped\u003cProductSearchService\u003e();\n```\n\n## 🏛️ Domain-Driven Design Features\n\nThe library provides comprehensive support for Domain-Driven Design patterns.\n\n### Aggregate Roots\n\nAggregate Roots are the entry points to your aggregates and ensure consistency boundaries:\n\n```csharp\nusing FS.EntityFramework.Library.Common;\nusing FS.EntityFramework.Library.Domain;\n\npublic class OrderAggregate : AggregateRoot\u003cGuid\u003e\n{\n    private readonly List\u003cOrderItem\u003e _items = new();\n    \n    public string OrderNumber { get; private set; } = string.Empty;\n    public decimal TotalAmount { get; private set; }\n    public DateTime OrderDate { get; private set; }\n    \n    // Read-only access to items\n    public IReadOnlyCollection\u003cOrderItem\u003e Items =\u003e _items.AsReadOnly();\n    \n    // Factory method enforcing business rules\n    public static OrderAggregate Create(string orderNumber)\n    {\n        DomainGuard.AgainstNullOrWhiteSpace(orderNumber, nameof(orderNumber));\n        \n        // AggregateRoot base class automatically generates Guid.CreateVersion7() in default constructor\n        var order = new OrderAggregate\n        {\n            OrderNumber = orderNumber,\n            OrderDate = DateTime.UtcNow,\n            TotalAmount = 0\n        };\n        \n        // Raise domain event\n        order.RaiseDomainEvent(new OrderCreatedEvent(order.Id, orderNumber));\n        \n        return order;\n    }\n    \n    // Business method with domain logic\n    public void AddItem(string productName, decimal unitPrice, int quantity)\n    {\n        DomainGuard.AgainstNullOrWhiteSpace(productName, nameof(productName));\n        DomainGuard.AgainstNegativeOrZero(unitPrice, nameof(unitPrice));\n        DomainGuard.AgainstNegativeOrZero(quantity, nameof(quantity));\n        \n        var item = new OrderItem(productName, unitPrice, quantity);\n        _items.Add(item);\n        \n        RecalculateTotal();\n        RaiseDomainEvent(new OrderItemAddedEvent(Id, productName, quantity));\n    }\n    \n    private void RecalculateTotal()\n    {\n        TotalAmount = _items.Sum(i =\u003e i.TotalPrice);\n    }\n}\n\npublic class OrderItem\n{\n    public string ProductName { get; }\n    public decimal UnitPrice { get; }\n    public int Quantity { get; }\n    public decimal TotalPrice =\u003e UnitPrice * Quantity;\n    \n    public OrderItem(string productName, decimal unitPrice, int quantity)\n    {\n        ProductName = productName;\n        UnitPrice = unitPrice;\n        Quantity = quantity;\n    }\n}\n```\n\n### Value Objects\n\nValue Objects encapsulate business concepts and ensure type safety:\n\n```csharp\nusing FS.EntityFramework.Library.Common;\nusing FS.EntityFramework.Library.Domain;\n\npublic class Money : ValueObject\n{\n    public decimal Amount { get; }\n    public string Currency { get; }\n    \n    public Money(decimal amount, string currency = \"USD\")\n    {\n        DomainGuard.AgainstNegative(amount, nameof(amount));\n        DomainGuard.AgainstNullOrWhiteSpace(currency, nameof(currency));\n        \n        Amount = amount;\n        Currency = currency;\n    }\n    \n    public static Money Zero =\u003e new(0);\n    public static Money FromDecimal(decimal amount) =\u003e new(amount);\n    \n    // Value object operations\n    public Money Add(Money other)\n    {\n        if (Currency != other.Currency)\n            throw new InvalidOperationException(\"Cannot add money with different currencies\");\n        \n        return new Money(Amount + other.Amount, Currency);\n    }\n    \n    protected override IEnumerable\u003cobject\u003e GetEqualityComponents()\n    {\n        yield return Amount;\n        yield return Currency;\n    }\n    \n    // Operators\n    public static Money operator +(Money left, Money right) =\u003e left.Add(right);\n}\n```\n\n### Business Rules\n\nImplement business rules for comprehensive domain validation:\n\n```csharp\nusing FS.EntityFramework.Library.Domain;\n\n// Simple business rule implementation\npublic class OrderMustHaveItemsRule : BusinessRule\n{\n    private readonly IReadOnlyCollection\u003cOrderItem\u003e _items;\n    \n    public OrderMustHaveItemsRule(IReadOnlyCollection\u003cOrderItem\u003e items)\n    {\n        _items = items;\n    }\n    \n    public override bool IsBroken() =\u003e _items.Count == 0;\n    \n    public override string Message =\u003e \"Order must have at least one item\";\n    \n    public override string ErrorCode =\u003e \"ORDER_NO_ITEMS\";\n}\n\n// Complex business rule with dependencies\npublic class CustomerCreditLimitRule : BusinessRule\n{\n    private readonly decimal _orderAmount;\n    private readonly decimal _currentCredit;\n    private readonly decimal _creditLimit;\n    \n    public CustomerCreditLimitRule(decimal orderAmount, decimal currentCredit, decimal creditLimit)\n    {\n        _orderAmount = orderAmount;\n        _currentCredit = currentCredit;\n        _creditLimit = creditLimit;\n    }\n    \n    public override bool IsBroken() =\u003e (_currentCredit + _orderAmount) \u003e _creditLimit;\n    \n    public override string Message =\u003e \n        $\"Order amount {_orderAmount:C} would exceed credit limit. Available credit: {(_creditLimit - _currentCredit):C}\";\n    \n    public override string ErrorCode =\u003e \"CREDIT_LIMIT_EXCEEDED\";\n}\n\n// Usage in aggregate with DomainGuard\npublic void ProcessOrder()\n{\n    // Check multiple business rules\n    DomainGuard.Against(\n        new OrderMustHaveItemsRule(_items),\n        new CustomerCreditLimitRule(TotalAmount, _customer.CurrentCredit, _customer.CreditLimit)\n    );\n    \n    // Alternative: Check individual rules\n    CheckRule(new OrderMustHaveItemsRule(_items));\n    \n    // Process the order...\n}\n```\n\n### Enhanced Domain Guard Usage\n\nDomainGuard provides comprehensive validation utilities:\n\n```csharp\nusing FS.EntityFramework.Library.Domain;\n\npublic class OrderAggregate : AggregateRoot\u003cGuid\u003e\n{\n    public void AddItem(string productName, decimal unitPrice, int quantity)\n    {\n        // Guard against null/empty values\n        DomainGuard.AgainstNullOrEmpty(productName, nameof(productName));\n        \n        // Guard against invalid values\n        DomainGuard.Against(unitPrice \u003c= 0, \"Unit price must be positive\", \"INVALID_UNIT_PRICE\");\n        DomainGuard.Against(quantity \u003c= 0, \"Quantity must be positive\", \"INVALID_QUANTITY\");\n        \n        // Guard against business rule violations\n        DomainGuard.Against(new MaxItemsPerOrderRule(_items.Count));\n        \n        // Guard against null objects\n        var product = _productService.GetProduct(productName);\n        DomainGuard.AgainstNull(product, nameof(product));\n        \n        // Business logic continues...\n        var item = new OrderItem(productName, unitPrice, quantity);\n        _items.Add(item);\n        \n        RaiseDomainEvent(new OrderItemAddedEvent(Id, productName, quantity));\n    }\n    \n    // Guard utilities for common scenarios\n    public void SetCustomerInfo(string customerId, string customerName)\n    {\n        DomainGuard.AgainstNullOrWhiteSpace(customerId, nameof(customerId));\n        DomainGuard.AgainstNullOrWhiteSpace(customerName, nameof(customerName));\n        DomainGuard.Against(customerId.Length \u003e 50, \"Customer ID too long\", \"CUSTOMER_ID_TOO_LONG\");\n        \n        _customerId = customerId;\n        _customerName = customerName;\n    }\n}\n```\n\n### Domain Specifications\n\nBuild reusable domain logic with specifications and combine them for complex queries:\n\n```csharp\nusing FS.EntityFramework.Library.Domain;\n\n// Basic specification\npublic class ExpensiveProductsSpecification : DomainSpecification\u003cProduct\u003e\n{\n    private readonly decimal _minimumPrice;\n    \n    public ExpensiveProductsSpecification(decimal minimumPrice)\n    {\n        _minimumPrice = minimumPrice;\n    }\n    \n    public override bool IsSatisfiedBy(Product candidate)\n    {\n        return candidate.Price \u003e= _minimumPrice;\n    }\n    \n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression()\n    {\n        return product =\u003e product.Price \u003e= _minimumPrice;\n    }\n}\n\n// Category-based specification\npublic class ProductsInCategorySpecification : DomainSpecification\u003cProduct\u003e\n{\n    private readonly int _categoryId;\n    \n    public ProductsInCategorySpecification(int categoryId)\n    {\n        _categoryId = categoryId;\n    }\n    \n    public override bool IsSatisfiedBy(Product candidate)\n    {\n        return candidate.CategoryId == _categoryId;\n    }\n    \n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression()\n    {\n        return product =\u003e product.CategoryId == _categoryId;\n    }\n}\n\n// Available products specification\npublic class AvailableProductsSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public override bool IsSatisfiedBy(Product candidate)\n    {\n        return !candidate.IsDeleted \u0026\u0026 candidate.Stock \u003e 0;\n    }\n    \n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression()\n    {\n        return product =\u003e !product.IsDeleted \u0026\u0026 product.Stock \u003e 0;\n    }\n}\n\n// Specification combinations\npublic class ProductSearchService\n{\n    private readonly IDomainRepository\u003cProduct, int\u003e _repository;\n    \n    public async Task\u003cIEnumerable\u003cProduct\u003e\u003e FindProductsAsync(ProductSearchCriteria criteria)\n    {\n        // Start with base specification\n        ISpecification\u003cProduct\u003e specification = new AvailableProductsSpecification();\n        \n        // Combine with price filter if specified\n        if (criteria.MinimumPrice.HasValue)\n        {\n            var priceSpec = new ExpensiveProductsSpecification(criteria.MinimumPrice.Value);\n            specification = specification.And(priceSpec);\n        }\n        \n        // Combine with category filter if specified\n        if (criteria.CategoryId.HasValue)\n        {\n            var categorySpec = new ProductsInCategorySpecification(criteria.CategoryId.Value);\n            specification = specification.And(categorySpec);\n        }\n        \n        // Execute combined specification\n        return await _repository.FindAsync(specification);\n    }\n    \n    // Advanced specification combinations\n    public async Task\u003cIEnumerable\u003cProduct\u003e\u003e FindPremiumOrDiscountedProductsAsync()\n    {\n        var expensiveSpec = new ExpensiveProductsSpecification(1000);\n        var discountedSpec = new DiscountedProductsSpecification();\n        \n        // OR combination: expensive OR discounted products\n        var combinedSpec = expensiveSpec.Or(discountedSpec);\n        \n        return await _repository.FindAsync(combinedSpec);\n    }\n    \n    public async Task\u003cIEnumerable\u003cProduct\u003e\u003e FindNonExpensiveProductsAsync()\n    {\n        var expensiveSpec = new ExpensiveProductsSpecification(500);\n        \n        // NOT combination: products that are NOT expensive\n        var nonExpensiveSpec = expensiveSpec.Not();\n        \n        return await _repository.FindAsync(nonExpensiveSpec);\n    }\n}\n\n// Complex specification with multiple conditions\npublic class PremiumProductsSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public override bool IsSatisfiedBy(Product candidate)\n    {\n        return candidate.Price \u003e= 1000 \u0026\u0026 \n               candidate.Rating \u003e= 4.5 \u0026\u0026 \n               !candidate.IsDeleted;\n    }\n    \n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression()\n    {\n        return product =\u003e product.Price \u003e= 1000 \u0026\u0026 \n                         product.Rating \u003e= 4.5 \u0026\u0026 \n                         !product.IsDeleted;\n    }\n}\n```\n\n### Advanced Specification Features\n\nThe `DomainSpecification\u003cT\u003e` class provides powerful features for building complex queries:\n\n#### 1. Pagination Support\n\n```csharp\npublic class PagedProductsSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public PagedProductsSpecification(int pageIndex, int pageSize)\n    {\n        // 0-based pagination\n        ApplyPagingByIndex(pageIndex, pageSize);\n        AddOrderBy(p =\u003e p.Name);\n    }\n    \n    public override bool IsSatisfiedBy(Product candidate) =\u003e true;\n    \n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression()\n    {\n        return product =\u003e !product.IsDeleted;\n    }\n}\n\n// Alternative: Skip/Take based pagination\npublic class OffsetProductsSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public OffsetProductsSpecification(int skip, int take)\n    {\n        ApplyPagingBySkipAndTake(skip, take);\n    }\n    \n    public override bool IsSatisfiedBy(Product candidate) =\u003e true;\n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression() =\u003e p =\u003e true;\n}\n```\n\n#### 2. Sorting and Ordering\n\n```csharp\npublic class SortedProductsSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public SortedProductsSpecification()\n    {\n        // Multiple order expressions applied in sequence\n        AddOrderByDescending(p =\u003e p.CreatedAt);  // Primary sort\n        AddOrderBy(p =\u003e p.Name);                  // Secondary sort (ThenBy)\n        AddOrderBy(p =\u003e p.Price);                 // Tertiary sort\n    }\n    \n    public override bool IsSatisfiedBy(Product candidate) =\u003e true;\n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression() =\u003e p =\u003e !p.IsDeleted;\n}\n```\n\n#### 3. Text Search Across Properties\n\n```csharp\npublic class ProductSearchSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public ProductSearchSpecification(string searchTerm)\n    {\n        // Search across multiple properties (case-insensitive Contains)\n        ApplySearch(searchTerm, \n            p =\u003e p.Name, \n            p =\u003e p.Description, \n            p =\u003e p.Brand,\n            p =\u003e p.Category.Name);\n        \n        AsNoTracking(); // Read-only query optimization\n    }\n    \n    public override bool IsSatisfiedBy(Product candidate)\n    {\n        return !candidate.IsDeleted;\n    }\n    \n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression()\n    {\n        return product =\u003e !product.IsDeleted;\n    }\n}\n```\n\n#### 4. Eager Loading with Includes\n\n```csharp\npublic class ProductWithRelationsSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public ProductWithRelationsSpecification()\n    {\n        // Expression-based includes\n        AddInclude(p =\u003e p.Category);\n        AddInclude(p =\u003e p.Supplier);\n        \n        // String-based includes for nested properties\n        AddInclude(\"Reviews.User\");\n        AddInclude(\"OrderItems.Order\");\n        \n        // Multiple includes at once\n        AddIncludes(\n            p =\u003e p.Images,\n            p =\u003e p.Tags,\n            p =\u003e p.Variants\n        );\n        \n        // Prevent Cartesian explosion with split queries\n        EnableSplitQuery();\n    }\n    \n    public override bool IsSatisfiedBy(Product candidate) =\u003e true;\n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression() =\u003e p =\u003e !p.IsDeleted;\n}\n```\n\n#### 5. Query Filters and Tracking Control\n\n```csharp\npublic class AllProductsIncludingDeletedSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public AllProductsIncludingDeletedSpecification()\n    {\n        // Ignore global query filters (e.g., soft delete filter)\n        ApplyIgnoreQueryFilters();\n        \n        // Enable tracking for updates\n        EnableTracking();\n    }\n    \n    public override bool IsSatisfiedBy(Product candidate) =\u003e true;\n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression() =\u003e p =\u003e true;\n}\n```\n\n#### 6. Grouping for Aggregations\n\n```csharp\npublic class ProductsByCategorySpecification : DomainSpecification\u003cProduct\u003e\n{\n    public ProductsByCategorySpecification()\n    {\n        ApplyGroupBy(p =\u003e p.CategoryId);\n        AddOrderBy(p =\u003e p.CategoryId);\n    }\n    \n    public override bool IsSatisfiedBy(Product candidate) =\u003e !candidate.IsDeleted;\n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression() =\u003e p =\u003e !p.IsDeleted;\n}\n```\n\n#### 7. Complex Real-World Example\n\n```csharp\npublic class AdvancedProductSearchSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public AdvancedProductSearchSpecification(\n        string? searchTerm = null,\n        decimal? minPrice = null,\n        decimal? maxPrice = null,\n        int? categoryId = null,\n        int pageIndex = 0,\n        int pageSize = 20,\n        bool includeDeleted = false)\n    {\n        // Dynamic criteria - only applied when parameter has value\n        AddCriteriaIf(minPrice.HasValue, p =\u003e p.Price \u003e= minPrice!.Value);\n        AddCriteriaIf(maxPrice.HasValue, p =\u003e p.Price \u003c= maxPrice!.Value);\n        AddCriteriaIf(categoryId.HasValue, p =\u003e p.CategoryId == categoryId!.Value);\n\n        // Text search if provided\n        if (!string.IsNullOrWhiteSpace(searchTerm))\n        {\n            ApplySearch(searchTerm, p =\u003e p.Name, p =\u003e p.Description);\n        }\n\n        // Eager load relations\n        AddIncludes(\n            p =\u003e p.Category,\n            p =\u003e p.Supplier,\n            p =\u003e p.Reviews\n        );\n\n        // Use split query for multiple collections\n        EnableSplitQuery();\n\n        // Sorting\n        AddOrderByDescending(p =\u003e p.CreatedAt);\n        AddOrderBy(p =\u003e p.Name);\n\n        // Pagination\n        ApplyPagingByIndex(pageIndex, pageSize);\n\n        // Include soft-deleted if requested\n        if (includeDeleted)\n        {\n            ApplyIgnoreQueryFilters();\n        }\n\n        // Read-only optimization\n        AsNoTracking();\n    }\n\n    public override bool IsSatisfiedBy(Product candidate)\n    {\n        return !candidate.IsDeleted;\n    }\n\n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression()\n    {\n        return product =\u003e !product.IsDeleted;\n    }\n}\n\n// Usage in repository\npublic class ProductService\n{\n    private readonly IDomainRepository\u003cProduct, int\u003e _repository;\n    \n    public async Task\u003cIEnumerable\u003cProduct\u003e\u003e SearchProductsAsync(\n        string searchTerm, \n        int page, \n        int pageSize)\n    {\n        var specification = new AdvancedProductSearchSpecification(\n            searchTerm: searchTerm,\n            minPrice: 10,\n            maxPrice: 1000,\n            pageIndex: page,\n            pageSize: pageSize\n        );\n        \n        return await _repository.FindAsync(specification);\n    }\n}\n```\n\n#### Dynamic Criteria with AddCriteria / AddCriteriaIf (v10.0.2+)\n\nBuild dynamic queries with optional filters directly in specifications:\n\n```csharp\npublic class ProductSearchSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public ProductSearchSpecification(\n        string? categoryName = null,\n        decimal? minPrice = null,\n        decimal? maxPrice = null,\n        bool? isActive = null,\n        string? searchTerm = null)\n    {\n        // Conditional criteria - only applied when parameter has value\n        AddCriteriaIf(!string.IsNullOrEmpty(categoryName),\n            p =\u003e p.Category.Name == categoryName!);\n\n        AddCriteriaIf(minPrice.HasValue,\n            p =\u003e p.Price \u003e= minPrice!.Value);\n\n        AddCriteriaIf(maxPrice.HasValue,\n            p =\u003e p.Price \u003c= maxPrice!.Value);\n\n        AddCriteriaIf(isActive.HasValue,\n            p =\u003e p.IsActive == isActive!.Value);\n\n        // Always-applied criteria\n        AddCriteria(p =\u003e !p.IsDeleted);\n\n        // Search\n        if (!string.IsNullOrEmpty(searchTerm))\n            ApplySearch(searchTerm, p =\u003e p.Name, p =\u003e p.Description);\n\n        AddOrderByDescending(p =\u003e p.CreatedAt);\n    }\n\n    public override bool IsSatisfiedBy(Product candidate) =\u003e !candidate.IsDeleted;\n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression() =\u003e p =\u003e true;\n}\n```\n\n#### Filtered Include (v10.0.2+)\n\nEF Core's filtered include is supported through `IncludeCollection`:\n\n```csharp\npublic class BlogWithActivePostsSpecification : DomainSpecification\u003cBlog\u003e\n{\n    public BlogWithActivePostsSpecification()\n    {\n        // Filtered include - only load active posts\n        IncludeCollection(b =\u003e b.Posts.Where(p =\u003e p.IsPublished \u0026\u0026 !p.IsDeleted))\n            .ThenInclude(p =\u003e p.Author);\n\n        // Regular include\n        Include(b =\u003e b.Owner);\n    }\n\n    public override bool IsSatisfiedBy(Blog candidate) =\u003e true;\n    public override Expression\u003cFunc\u003cBlog, bool\u003e\u003e ToExpression() =\u003e b =\u003e true;\n}\n```\n\n#### Type-Safe ThenInclude Support (v10.0.2+)\n\n```csharp\npublic class OrderWithDetailsSpecification : DomainSpecification\u003cOrder\u003e\n{\n    public OrderWithDetailsSpecification(Guid orderId)\n    {\n        // Type-safe ThenInclude chaining\n        Include(order =\u003e order.Customer)\n            .ThenInclude(customer =\u003e customer.Address);\n\n        // Collection ThenInclude\n        IncludeCollection(order =\u003e order.OrderItems)\n            .ThenInclude(item =\u003e item.Product)\n            .ThenInclude(product =\u003e product.Category);\n\n        // Multiple levels deep\n        IncludeCollection(order =\u003e order.Payments)\n            .ThenInclude(payment =\u003e payment.PaymentMethod);\n\n        AsTracking(); // Enable tracking for updates\n    }\n\n    public override bool IsSatisfiedBy(Order candidate) =\u003e true;\n    public override Expression\u003cFunc\u003cOrder, bool\u003e\u003e ToExpression() =\u003e o =\u003e o.Id == orderId;\n}\n```\n\n#### Specification with Pagination (FindPagedAsync) (v10.0.2+)\n\n```csharp\nvar specification = new ActiveProductsSpecification(pageIndex: 0, pageSize: 20);\n\n// Returns IPaginate\u003cProduct\u003e with total count, pages, etc.\nvar pagedResult = await repository.FindPagedAsync(specification);\n\n// With projection\nvar pagedDtos = await repository.FindPagedAsync(\n    specification,\n    selector: p =\u003e new ProductDto { Id = p.Id, Name = p.Name });\n```\n\n#### Single Entity from Specification (v10.0.2+)\n\n```csharp\n// FirstOrDefaultAsync with specification\nvar product = await repository.FirstOrDefaultAsync(specification);\n\n// SingleOrDefaultAsync with specification (throws if multiple)\nvar uniqueProduct = await repository.SingleOrDefaultAsync(specification);\n\n// FirstOrDefaultAsync with projection\nvar dto = await repository.FirstOrDefaultAsync(\n    specification,\n    selector: p =\u003e new ProductDto { Id = p.Id, Name = p.Name });\n```\n\n#### Specification Composition Summary\n\n**Available Methods:**\n\n**Includes:**\n- `AddInclude(expression)` - Simple eager load navigation property\n- `AddInclude(string)` - String-based include for nested properties\n- `AddIncludes(expressions...)` - Multiple includes at once\n- `Include\u003cTProperty\u003e(expression)` - Type-safe include with ThenInclude support\n- `IncludeCollection\u003cTProperty\u003e(expression)` - Collection include with ThenInclude support (supports filtered include)\n- `ClearIncludes()` - Remove all includes\n\n**Ordering:**\n- `AddOrderBy(expression)` - Ascending sort\n- `AddOrderByDescending(expression)` - Descending sort\n- `ClearOrdering()` - Reset all ordering\n\n**Pagination \u0026 Limiting:**\n- `ApplyPagingByIndex(pageIndex, pageSize)` - 0-based page pagination\n- `ApplyPagingBySkipAndTake(skip, take)` - Offset-based pagination\n- `ApplyLimit(count)` - Limit results without pagination metadata\n\n**Filtering \u0026 Criteria:**\n- `AddCriteria(predicate)` - Add an additional filter predicate\n- `AddCriteriaIf(condition, predicate)` - Conditionally add a filter predicate\n- `ClearCriteria()` - Remove all additional criteria\n- `ApplySearch(term, properties...)` - Text search across properties\n- `ApplyIgnoreQueryFilters()` - Bypass global filters\n- `ApplyDistinct()` - Return only distinct results\n\n**Grouping:**\n- `ApplyGroupBy(expression)` - Group results\n\n**Projection:**\n- `ApplySelector\u003cTResult\u003e(expression)` - Define projection in specification\n\n**Tracking:**\n- `AsNoTracking()` - Disable change tracking (default)\n- `AsTracking()` / `EnableTracking()` - Enable change tracking\n- `AsNoTrackingWithIdentityResolution()` - No tracking with identity resolution\n\n**Query Optimization:**\n- `EnableSplitQuery()` - Prevent Cartesian explosion\n- `TagWith(tag)` - Add query tag for debugging/logging\n\n**Composition:**\n- `And(spec)`, `Or(spec)`, `Not()` - Logical combinations\n\n## 📊 Advanced Features\n\n### Interceptor System\n\nThe library provides a robust interceptor system that automatically handles cross-cutting concerns:\n\n#### Audit Interceptor\n\nAutomatically tracks entity creation and modification:\n\n```csharp\n// Automatic configuration via Fluent API\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithAudit()\n        .UsingHttpContext() // Uses current HTTP user\n    .Build();\n\n// Manual interceptor registration\nservices.AddScoped\u003cAuditInterceptor\u003e(provider =\u003e\n{\n    var userProvider = () =\u003e provider.GetService\u003cIHttpContextAccessor\u003e()\n        ?.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;\n    return new AuditInterceptor(userProvider);\n});\n```\n\n#### Soft Delete Interceptor\n\nAutomatically handles soft delete operations:\n\n```csharp\n// Entities implementing ISoftDelete are automatically soft deleted\npublic class Product : BaseAuditableEntity\u003cint\u003e, ISoftDelete\n{\n    public string Name { get; set; } = string.Empty;\n    \n    // ISoftDelete properties (automatically managed)\n    public bool IsDeleted { get; set; }\n    public DateTime? DeletedAt { get; set; }\n    public string? DeletedBy { get; set; }\n}\n\n// Configuration\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithSoftDelete() // Enables soft delete interceptor\n    .Build();\n\n// Usage - automatically becomes soft delete\nvar repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\nawait repository.DeleteAsync(product); // Soft delete\nawait repository.RestoreAsync(productId); // Restore\n```\n\n#### ID Generation Interceptor\n\nAutomatically generates IDs for new entities:\n\n```csharp\n// Register ID generators\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithIdGeneration()\n        .WithGenerator\u003cGuid, GuidV7Generator\u003e() // GUID V7 for Guid properties\n        .WithGenerator\u003cstring, CustomStringIdGenerator\u003e() // Custom string IDs\n    .Complete()\n    .Build();\n\n// Custom ID generator example\npublic class CustomStringIdGenerator : IIdGenerator\u003cstring\u003e\n{\n    public Type KeyType =\u003e typeof(string);\n    \n    public string Generate()\n    {\n        return $\"PROD_{DateTime.UtcNow:yyyyMMdd}_{Guid.NewGuid():N}\"[..20];\n    }\n    \n    object IIdGenerator.Generate() =\u003e Generate();\n}\n```\n\n### FluentConfiguration API Reference\n\nThe Fluent Configuration API provides a clean, type-safe way to configure all library features:\n\n#### Core Configuration Methods\n\n```csharp\n// Start configuration\nservices.AddFSEntityFramework\u003cTDbContext\u003e()\n    \n    // Audit Configuration Chain\n    .WithAudit()\n        .UsingHttpContext()                    // Use HTTP context for user\n        .UsingUserProvider(provider =\u003e \"user\") // Custom user provider\n        .UsingUserContext\u003cIUserContext\u003e()      // Interface-based user context\n        .UsingTimeProvider(provider =\u003e DateTime.UtcNow) // Custom time provider\n    .Complete() // End audit configuration\n    \n    // Domain Events Configuration Chain\n    .WithDomainEvents()\n        .UsingDefaultDispatcher()              // Use built-in dispatcher\n        .UsingCustomDispatcher\u003cTDispatcher\u003e()  // Custom dispatcher\n        .WithAutoHandlerDiscovery()            // Auto-discover handlers\n        .WithHandlerDiscovery(assembly)        // Discover from specific assembly\n        .WithAttributedHandlers(assembly)      // Use attributed handlers\n    .Complete() // End domain events configuration\n    \n    // Soft Delete Configuration\n    .WithSoftDelete()\n    \n    // ID Generation Configuration Chain\n    .WithIdGeneration()\n        .WithGenerator\u003cTKey, TGenerator\u003e()     // Register generator for type\n        .WithFactory\u003cTFactory\u003e()               // Custom factory\n    .Complete() // End ID generation configuration\n    \n    // Validation and Build\n    .ValidateConfiguration()                   // Validate all configurations\n    .Build();                                 // Build and register services\n```\n\n#### Configuration Validation\n\n```csharp\n// The fluent API includes built-in validation\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithAudit()\n        .UsingHttpContext()\n    .WithDomainEvents()\n        .UsingDefaultDispatcher()\n        .WithAutoHandlerDiscovery()\n    .Complete()\n    .ValidateConfiguration() // Throws detailed exceptions for invalid configs\n    .Build();\n```\n\n### Infrastructure Layer Details\n\nThe library provides a complete infrastructure layer implementing DDD patterns:\n\n#### Domain Repository Implementation\n\n```csharp\n// IDomainRepository interface for aggregate roots\npublic interface IDomainRepository\u003cTAggregate, TKey\u003e\n    where TAggregate : AggregateRoot\u003cTKey\u003e\n    where TKey : IEquatable\u003cTKey\u003e\n{\n    // Core CRUD\n    Task\u003cTAggregate?\u003e GetByIdAsync(TKey id, List\u003cExpression\u003cFunc\u003cTAggregate, object\u003e\u003e\u003e? includes = null, bool disableTracking = false, CancellationToken cancellationToken = default);\n    Task\u003cTAggregate\u003e GetByIdRequiredAsync(TKey id, List\u003cExpression\u003cFunc\u003cTAggregate, object\u003e\u003e\u003e? includes = null, bool disableTracking = false, CancellationToken cancellationToken = default);\n    Task AddAsync(TAggregate aggregate, CancellationToken cancellationToken = default);\n    Task UpdateAsync(TAggregate aggregate, CancellationToken cancellationToken = default);\n    Task RemoveAsync(TAggregate aggregate, CancellationToken cancellationToken = default);\n\n    // Specification queries\n    Task\u003cIEnumerable\u003cTAggregate\u003e\u003e FindAsync(ISpecification\u003cTAggregate\u003e specification, CancellationToken cancellationToken = default);\n    Task\u003cbool\u003e AnyAsync(ISpecification\u003cTAggregate\u003e specification, CancellationToken cancellationToken = default);\n    Task\u003cint\u003e CountAsync(ISpecification\u003cTAggregate\u003e specification, CancellationToken cancellationToken = default);\n\n    // Single entity from specification\n    Task\u003cTAggregate?\u003e FirstOrDefaultAsync(ISpecification\u003cTAggregate\u003e specification, CancellationToken cancellationToken = default);\n    Task\u003cTAggregate?\u003e SingleOrDefaultAsync(ISpecification\u003cTAggregate\u003e specification, CancellationToken cancellationToken = default);\n\n    // Projection methods\n    Task\u003cTResult?\u003e GetByIdAsync\u003cTResult\u003e(TKey id, Expression\u003cFunc\u003cTAggregate, TResult\u003e\u003e selector, CancellationToken cancellationToken = default);\n    Task\u003cIEnumerable\u003cTResult\u003e\u003e FindAsync\u003cTResult\u003e(ISpecification\u003cTAggregate\u003e specification, Expression\u003cFunc\u003cTAggregate, TResult\u003e\u003e selector, CancellationToken cancellationToken = default);\n    Task\u003cIEnumerable\u003cTResult\u003e\u003e FindWithSelectorAsync\u003cTResult\u003e(ISpecification\u003cTAggregate\u003e specification, CancellationToken cancellationToken = default);\n    Task\u003cTResult?\u003e FirstOrDefaultAsync\u003cTResult\u003e(ISpecification\u003cTAggregate\u003e specification, Expression\u003cFunc\u003cTAggregate, TResult\u003e\u003e selector, CancellationToken cancellationToken = default);\n\n    // Paginated results\n    Task\u003cIPaginate\u003cTAggregate\u003e\u003e FindPagedAsync(ISpecification\u003cTAggregate\u003e specification, CancellationToken cancellationToken = default);\n    Task\u003cIPaginate\u003cTResult\u003e\u003e FindPagedAsync\u003cTResult\u003e(ISpecification\u003cTAggregate\u003e specification, Expression\u003cFunc\u003cTAggregate, TResult\u003e\u003e selector, CancellationToken cancellationToken = default);\n}\n\n// Usage with automatic registration\nservices.AddDomainServices()\n    .AddDomainRepository\u003cOrderAggregate, Guid\u003e()\n    .AddDomainRepository\u003cCustomerAggregate, Guid\u003e();\n\n// Custom repository implementation\npublic class OrderRepository : DomainRepository\u003cOrderAggregate, Guid\u003e, IOrderRepository\n{\n    public OrderRepository(DbContext context, IServiceProvider serviceProvider) \n        : base(context, serviceProvider) { }\n    \n    public async Task\u003cOrderAggregate?\u003e FindByOrderNumberAsync(string orderNumber)\n    {\n        return await FirstOrDefaultAsync(new OrderByNumberSpecification(orderNumber));\n    }\n}\n```\n\n#### Domain Unit of Work\n\n```csharp\n// IDomainUnitOfWork for aggregate-focused operations\npublic interface IDomainUnitOfWork : IDisposable\n{\n    IDomainRepository\u003cTAggregate, TKey\u003e GetRepository\u003cTAggregate, TKey\u003e()\n        where TAggregate : AggregateRoot\u003cTKey\u003e\n        where TKey : IEquatable\u003cTKey\u003e;\n    \n    Task\u003cint\u003e SaveChangesAsync(CancellationToken cancellationToken = default);\n    Task BeginTransactionAsync(CancellationToken cancellationToken = default);\n    Task CommitTransactionAsync(CancellationToken cancellationToken = default);\n    Task RollbackTransactionAsync(CancellationToken cancellationToken = default);\n}\n\n// Usage in application services\npublic class OrderApplicationService\n{\n    private readonly IDomainUnitOfWork _domainUnitOfWork;\n    \n    public async Task ProcessOrderAsync(ProcessOrderCommand command)\n    {\n        var orderRepository = _domainUnitOfWork.GetRepository\u003cOrderAggregate, Guid\u003e();\n        var order = await orderRepository.GetByIdAsync(command.OrderId);\n        \n        order?.ProcessOrder();\n        \n        await _domainUnitOfWork.SaveChangesAsync(); // Domain events dispatched automatically\n    }\n}\n```\n\n### Enhanced Pagination Support\n\nThe library provides comprehensive pagination capabilities:\n\n#### Basic Pagination\n\n```csharp\n// IPaginate interface provides rich pagination information\npublic interface IPaginate\u003cT\u003e\n{\n    int Index { get; }           // Current page index (0-based)\n    int Size { get; }            // Page size\n    int Count { get; }           // Total item count\n    int Pages { get; }           // Total page count\n    IList\u003cT\u003e Items { get; }      // Current page items\n    bool HasPrevious { get; }    // Has previous page\n    bool HasNext { get; }        // Has next page\n}\n\n// Repository pagination methods\nvar repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n\n// Simple pagination\nvar pagedProducts = await repository.GetPagedAsync(\n    pageIndex: 0,\n    pageSize: 20,\n    orderBy: query =\u003e query.OrderBy(p =\u003e p.Name)\n);\n\n// Pagination with includes\nvar pagedProductsWithCategory = await repository.GetPagedAsync(\n    pageIndex: 0,\n    pageSize: 20,\n    includes: new List\u003cExpression\u003cFunc\u003cProduct, object\u003e\u003e\u003e { p =\u003e p.Category },\n    orderBy: query =\u003e query.OrderBy(p =\u003e p.Name)\n);\n```\n\n#### Advanced Pagination with Filtering\n\n```csharp\n// Pagination with dynamic filtering\nvar filter = new FilterModel\n{\n    SearchTerm = \"laptop\", // Searches across all string properties\n    Filters = new List\u003cFilterItem\u003e\n    {\n        new() { Field = \"Price\", Operator = \"greaterthan\", Value = \"500\" },\n        new() { Field = \"CategoryId\", Operator = \"equals\", Value = \"1\" }\n    }\n};\n\nvar filteredPage = await repository.GetPagedWithFilterAsync(\n    filter,\n    pageIndex: 0,\n    pageSize: 20,\n    orderBy: query =\u003e query.OrderByDescending(p =\u003e p.CreatedAt),\n    includes: new List\u003cExpression\u003cFunc\u003cProduct, object\u003e\u003e\u003e { p =\u003e p.Category }\n);\n\n// Available filter operators (full name / alias):\n// \"equals\" (eq), \"notequals\" (neq), \"contains\", \"startswith\" (sw), \"endswith\" (ew)\n// \"greaterthan\" (gt), \"greaterthanorequal\" (gte), \"lessthan\" (lt), \"lessthanorequal\" (lte)\n// \"isnull\", \"isnotnull\", \"isempty\", \"isnotempty\" (no value required)\n// \"in\", \"notin\" (comma-separated values, e.g. \"1,2,3\")\n//\n// Or use the type-safe FilterOperator enum / FilterBuilder\u003cT\u003e for compile-time validation\n```\n\n#### Cursor-Based Pagination (v10.0.2+)\n\nCursor pagination is more efficient than offset pagination for large datasets:\n\n```csharp\n// Basic cursor pagination\nvar repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n\n// Get first page\nvar firstPage = await repository.GetCursorPagedAsync\u003cint\u003e(\n    pageSize: 20,\n    afterCursor: null,           // null for first page\n    beforeCursor: null,\n    cursorSelector: p =\u003e p.Id,   // Use ID as cursor\n    predicate: p =\u003e p.IsActive,\n    orderBy: q =\u003e q.OrderBy(p =\u003e p.Id)\n);\n\n// Get next page using LastCursor\nvar nextPage = await repository.GetCursorPagedAsync\u003cint\u003e(\n    pageSize: 20,\n    afterCursor: firstPage.LastCursor,  // Start after last item\n    beforeCursor: null,\n    cursorSelector: p =\u003e p.Id\n);\n\n// ICursorPaginate interface\n// - Items: Current page items\n// - Size: Requested page size\n// - Count: Actual items returned\n// - FirstCursor/LastCursor: Cursor values for navigation\n// - HasNext/HasPrevious: Navigation availability\n\n// Cursor pagination with projection\nvar projectedPage = await repository.GetCursorPagedAsync\u003cProductDto, int\u003e(\n    selector: p =\u003e new ProductDto { Id = p.Id, Name = p.Name, Price = p.Price },\n    pageSize: 20,\n    afterCursor: null,\n    beforeCursor: null,\n    cursorSelector: p =\u003e p.Id\n);\n```\n\n### Projection/Select Support (v10.0.2+)\n\nThe library provides comprehensive projection methods for efficient data retrieval:\n\n#### Repository Projection Methods\n\n```csharp\nvar repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n\n// Project single entity by ID\nvar productDto = await repository.GetByIdAsync(\n    id: 1,\n    selector: p =\u003e new ProductDto\n    {\n        Id = p.Id,\n        Name = p.Name,\n        CategoryName = p.Category.Name,\n        Price = p.Price\n    });\n\n// Project all entities\nvar allProductDtos = await repository.GetAllAsync(\n    selector: p =\u003e new ProductSummaryDto\n    {\n        Id = p.Id,\n        Name = p.Name\n    });\n\n// Project first match\nvar cheapestProduct = await repository.FirstOrDefaultAsync(\n    predicate: p =\u003e p.CategoryId == categoryId,\n    selector: p =\u003e new ProductDto { Id = p.Id, Name = p.Name, Price = p.Price });\n\n// Project single match (throws if multiple)\nvar uniqueProduct = await repository.SingleOrDefaultAsync(\n    predicate: p =\u003e p.Sku == \"ABC123\",\n    selector: p =\u003e new ProductDto { Id = p.Id, Name = p.Name });\n\n// Project with filter and ordering\nvar filteredProducts = await repository.FindAsync(\n    predicate: p =\u003e p.Price \u003e 100,\n    selector: p =\u003e new ProductDto { Id = p.Id, Name = p.Name, Price = p.Price },\n    orderBy: q =\u003e q.OrderByDescending(p =\u003e p.Price));\n\n// Paginated projection\nvar pagedProducts = await repository.GetPagedAsync(\n    selector: p =\u003e new ProductListDto\n    {\n        Id = p.Id,\n        Name = p.Name,\n        CategoryName = p.Category.Name\n    },\n    pageIndex: 0,\n    pageSize: 20,\n    predicate: p =\u003e p.IsActive,\n    orderBy: q =\u003e q.OrderBy(p =\u003e p.Name));\n\n// Filtered pagination with projection\nvar filteredPagedProducts = await repository.GetPagedWithFilterAsync(\n    selector: p =\u003e new ProductDto { Id = p.Id, Name = p.Name },\n    filter: filterModel,\n    pageIndex: 0,\n    pageSize: 20);\n\n// Specification with projection\nvar spec = new ActiveProductsSpecification();\nvar specProducts = await repository.GetAsync(spec,\n    selector: p =\u003e new ProductDto { Id = p.Id, Name = p.Name });\n```\n\n#### Domain Repository Projection Methods\n\n```csharp\nvar domainRepository = _domainUnitOfWork.GetRepository\u003cProductAggregate, Guid\u003e();\n\n// Project aggregate by ID\nvar productDto = await domainRepository.GetByIdAsync(\n    id: productId,\n    selector: p =\u003e new ProductDetailDto\n    {\n        Id = p.Id,\n        Name = p.Name,\n        TotalOrderCount = p.Orders.Count\n    });\n\n// Project with specification\nvar specification = new ActiveProductsSpecification();\nvar products = await domainRepository.FindAsync(\n    specification,\n    selector: p =\u003e new ProductSummaryDto { Id = p.Id, Name = p.Name });\n```\n\n#### Specification-Based Projection\n\nDefine projections directly in specifications:\n\n```csharp\npublic class ProductListSpecification : DomainSpecification\u003cProduct\u003e\n{\n    public ProductListSpecification(int categoryId, int pageIndex, int pageSize)\n    {\n        // Define the projection\n        ApplySelector\u003cProductListDto\u003e(p =\u003e new ProductListDto\n        {\n            Id = p.Id,\n            Name = p.Name,\n            CategoryName = p.Category.Name,\n            Price = p.Price,\n            ReviewCount = p.Reviews.Count\n        });\n\n        AddInclude(p =\u003e p.Category);\n        AddOrderBy(p =\u003e p.Name);\n        ApplyPagingByIndex(pageIndex, pageSize);\n    }\n\n    public override bool IsSatisfiedBy(Product candidate) =\u003e\n        candidate.CategoryId == categoryId;\n\n    public override Expression\u003cFunc\u003cProduct, bool\u003e\u003e ToExpression() =\u003e\n        p =\u003e p.CategoryId == categoryId;\n}\n\n// Usage\nvar specification = new ProductListSpecification(categoryId: 5, pageIndex: 0, pageSize: 20);\nvar results = await repository.FindWithSelectorAsync\u003cProductListDto\u003e(specification);\n```\n\n### Additional Query Methods (v10.0.2+)\n\n#### SingleOrDefaultAsync\n\nGet exactly one entity or null, throws if multiple match:\n\n```csharp\n// Entity version\nvar product = await repository.SingleOrDefaultAsync(\n    predicate: p =\u003e p.Sku == \"UNIQUE-SKU\",\n    includes: new List\u003cExpression\u003cFunc\u003cProduct, object\u003e\u003e\u003e { p =\u003e p.Category },\n    disableTracking: true);\n\n// Projection version\nvar productDto = await repository.SingleOrDefaultAsync(\n    predicate: p =\u003e p.Sku == \"UNIQUE-SKU\",\n    selector: p =\u003e new ProductDto { Id = p.Id, Name = p.Name });\n```\n\n#### AnyAsync with Predicate\n\nCheck existence with optional predicate:\n\n```csharp\n// Check if any products exist\nvar hasAnyProducts = await repository.AnyAsync();\n\n// Check with predicate\nvar hasExpensiveProducts = await repository.AnyAsync(p =\u003e p.Price \u003e 1000);\nvar hasActiveProducts = await repository.AnyAsync(p =\u003e p.IsActive \u0026\u0026 !p.IsDeleted);\n```\n\n### ID Generation Extensions\n\nThe library supports modular ID generation strategies:\n\n#### GUID Version 7 (Requires extension package)\n\n```csharp\n// Install: dotnet add package FS.EntityFramework.Library.GuidV7\n\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithGuidV7() // Automatic GUID V7 generation\n    .Build();\n\n// Entity with GUID V7\npublic class User : BaseAuditableEntity\u003cGuid\u003e\n{\n    public string Name { get; set; } = string.Empty;\n    public string Email { get; set; } = string.Empty;\n    \n    // ID will be automatically generated as GUID V7\n}\n```\n\n#### ULID (Requires extension package)\n\n```csharp\n// Install: dotnet add package FS.EntityFramework.Library.UlidGenerator\n\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithUlid() // Automatic ULID generation\n    .Build();\n\n// Entity with ULID\npublic class Order : BaseAuditableEntity\u003cUlid\u003e\n{\n    public string OrderNumber { get; set; } = string.Empty;\n    \n    // ID will be automatically generated as ULID\n}\n```\n\n### Advanced Audit Configuration\n\nConfigure audit tracking with different user context providers:\n\n```csharp\n// Web applications with HttpContext\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithAudit()\n        .UsingHttpContext() // Uses NameIdentifier claim\n    .Build();\n\n// Custom user provider\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithAudit()\n        .UsingUserProvider(provider =\u003e\n        {\n            var userService = provider.GetService\u003cICurrentUserService\u003e();\n            return userService?.GetCurrentUserId();\n        })\n    .Build();\n\n// Interface-based user context\npublic class ApplicationUserContext : IUserContext\n{\n    private readonly ICurrentUserService _userService;\n    \n    public ApplicationUserContext(ICurrentUserService userService)\n    {\n        _userService = userService;\n    }\n    \n    public string? CurrentUser =\u003e _userService.GetCurrentUserId();\n}\n\nservices.AddScoped\u003cIUserContext, ApplicationUserContext\u003e();\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithAudit()\n        .UsingUserContext\u003cIUserContext\u003e()\n    .Build();\n```\n\n### Comprehensive Configuration Example\n\nHere's a full-featured configuration example:\n\n```csharp\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    // Audit Configuration\n    .WithAudit()\n        .UsingHttpContext() // User tracking via HTTP context\n    \n    // Domain Events Configuration\n    .WithDomainEvents()\n        .UsingDefaultDispatcher() // Default event dispatcher\n        .WithAutoHandlerDiscovery() // Auto-discover event handlers\n    .Complete()\n    \n    // Soft Delete Configuration\n    .WithSoftDelete()\n    \n    // ID Generation Configuration\n    .WithIdGeneration()\n        .WithGenerator\u003cstring, CustomStringIdGenerator\u003e()\n    .Complete()\n    \n    // Validation \u0026 Build\n    .ValidateConfiguration()\n    .Build();\n```\n\n### Error Handling \u0026 Exception Management\n\nThe library provides comprehensive error handling patterns:\n\n```csharp\nusing FS.EntityFramework.Library.Domain;\n\n// Domain-specific exceptions\npublic class OrderDomainException : DomainException\n{\n    public OrderDomainException(string message) : base(message) { }\n    public OrderDomainException(string message, Exception innerException) : base(message, innerException) { }\n}\n\n// Business rule validation exception handling\npublic class OrderApplicationService\n{\n    private readonly IDomainUnitOfWork _unitOfWork;\n    private readonly ILogger\u003cOrderApplicationService\u003e _logger;\n    \n    public async Task\u003cOrderResult\u003e ProcessOrderAsync(ProcessOrderCommand command)\n    {\n        try\n        {\n            var repository = _unitOfWork.GetRepository\u003cOrderAggregate, Guid\u003e();\n            var order = await repository.GetByIdAsync(command.OrderId);\n            \n            if (order == null)\n            {\n                return OrderResult.NotFound(command.OrderId);\n            }\n            \n            // Business logic with domain validation\n            order.ProcessOrder();\n            \n            await _unitOfWork.SaveChangesAsync();\n            \n            return OrderResult.Success(order);\n        }\n        catch (BusinessRuleValidationException ex)\n        {\n            _logger.LogWarning(\"Business rule violation: {Rule} - {Message}\", \n                ex.BrokenRule.ErrorCode, ex.BrokenRule.Message);\n            return OrderResult.BusinessRuleViolation(ex.BrokenRule);\n        }\n        catch (DomainException ex)\n        {\n            _logger.LogError(ex, \"Domain error processing order {OrderId}\", command.OrderId);\n            return OrderResult.DomainError(ex.Message);\n        }\n        catch (Exception ex)\n        {\n            _logger.LogError(ex, \"Unexpected error processing order {OrderId}\", command.OrderId);\n            return OrderResult.UnexpectedError();\n        }\n    }\n}\n\n// Result pattern for better error handling\npublic class OrderResult\n{\n    public bool IsSuccess { get; private set; }\n    public string? ErrorMessage { get; private set; }\n    public string? ErrorCode { get; private set; }\n    public OrderAggregate? Order { get; private set; }\n    \n    public static OrderResult Success(OrderAggregate order) =\u003e \n        new() { IsSuccess = true, Order = order };\n    \n    public static OrderResult NotFound(Guid orderId) =\u003e \n        new() { IsSuccess = false, ErrorMessage = $\"Order {orderId} not found\", ErrorCode = \"ORDER_NOT_FOUND\" };\n    \n    public static OrderResult BusinessRuleViolation(IBusinessRule rule) =\u003e \n        new() { IsSuccess = false, ErrorMessage = rule.Message, ErrorCode = rule.ErrorCode };\n    \n    public static OrderResult DomainError(string message) =\u003e \n        new() { IsSuccess = false, ErrorMessage = message, ErrorCode = \"DOMAIN_ERROR\" };\n    \n    public static OrderResult UnexpectedError() =\u003e \n        new() { IsSuccess = false, ErrorMessage = \"An unexpected error occurred\", ErrorCode = \"UNEXPECTED_ERROR\" };\n}\n```\n\n### Performance Considerations\n\nOptimize your application with these performance best practices:\n\n#### Repository Query Optimization\n\n```csharp\n// ✅ Good: Use built-in projection methods (v10.0.2+)\npublic async Task\u003cIReadOnlyList\u003cProductSummaryDto\u003e\u003e GetProductSummariesAsync()\n{\n    var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n\n    // Built-in projection method - cleaner and more efficient\n    return await repository.GetAllAsync(p =\u003e new ProductSummaryDto\n    {\n        Id = p.Id,\n        Name = p.Name,\n        Price = p.Price,\n        CategoryName = p.Category.Name\n    });\n}\n\n// ✅ Good: Alternative using GetQueryable for complex scenarios\npublic async Task\u003cIEnumerable\u003cProductSummaryDto\u003e\u003e GetProductSummariesManualAsync()\n{\n    var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n\n    return await repository.GetQueryable(disableTracking: true)\n        .Select(p =\u003e new ProductSummaryDto\n        {\n            Id = p.Id,\n            Name = p.Name,\n            Price = p.Price,\n            CategoryName = p.Category.Name\n        })\n        .ToListAsync();\n}\n\n// ✅ Good: Use includes strategically\npublic async Task\u003cProduct?\u003e GetProductWithDetailsAsync(int id)\n{\n    var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n    \n    return await repository.GetQueryable()\n        .Include(p =\u003e p.Category)\n        .Include(p =\u003e p.Reviews.Take(5)) // Limit related data\n        .FirstOrDefaultAsync(p =\u003e p.Id == id);\n}\n\n// ✅ Good: Use compiled queries for frequently used queries\nprivate static readonly Func\u003cApplicationDbContext, int, Task\u003cProduct?\u003e\u003e GetProductByIdCompiled =\n    EF.CompileAsyncQuery((ApplicationDbContext context, int id) =\u003e\n        context.Products.FirstOrDefault(p =\u003e p.Id == id));\n\npublic async Task\u003cProduct?\u003e GetProductByIdOptimizedAsync(int id)\n{\n    return await GetProductByIdCompiled(_context, id);\n}\n```\n\n#### Bulk Operations\n\n```csharp\n// ✅ Good: Use bulk operations for large datasets\npublic async Task ImportProductsAsync(IEnumerable\u003cProduct\u003e products)\n{\n    var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n    \n    // Bulk insert for better performance\n    await repository.BulkInsertAsync(products, saveChanges: true);\n}\n\n// ✅ Good: Batch operations\npublic async Task UpdateMultipleProductPricesAsync(Dictionary\u003cint, decimal\u003e priceUpdates)\n{\n    var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n    \n    var productIds = priceUpdates.Keys.ToList();\n    var products = await repository.GetQueryable()\n        .Where(p =\u003e productIds.Contains(p.Id))\n        .ToListAsync();\n    \n    foreach (var product in products)\n    {\n        if (priceUpdates.TryGetValue(product.Id, out var newPrice))\n        {\n            product.SetPrice(newPrice);\n        }\n    }\n    \n    await _unitOfWork.SaveChangesAsync(); // Single save operation\n}\n```\n\n#### Caching Strategies\n\n```csharp\n// ✅ Good: Implement caching for frequently accessed data\npublic class CachedProductService\n{\n    private readonly IUnitOfWork _unitOfWork;\n    private readonly IMemoryCache _cache;\n    private readonly TimeSpan _cacheExpiry = TimeSpan.FromMinutes(15);\n    \n    public async Task\u003cProduct?\u003e GetProductAsync(int id)\n    {\n        var cacheKey = $\"product_{id}\";\n        \n        if (_cache.TryGetValue(cacheKey, out Product? cachedProduct))\n        {\n            return cachedProduct;\n        }\n        \n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n        var product = await repository.GetByIdAsync(id);\n        \n        if (product != null)\n        {\n            _cache.Set(cacheKey, product, _cacheExpiry);\n        }\n        \n        return product;\n    }\n}\n```\n\n### Diagnostics \u0026 Metrics (v10.0.3+)\n\nThe library provides opt-in OpenTelemetry-compatible metrics via `System.Diagnostics.Metrics`. Metrics are **disabled by default** and can be enabled via the fluent configuration API.\n\n#### Enable Metrics\n\n```csharp\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithMetrics()  // Enable production metrics\n    .WithAudit()\n        .UsingHttpContext()\n    .Build();\n```\n\n#### Available Metrics\n\n| Metric | Type | Description |\n|--------|------|-------------|\n| `repository.operations` | Counter | Total repository operations (tag: operation) |\n| `repository.operations.errors` | Counter | Repository operation errors (tags: operation, error_type) |\n| `repository.operation.duration` | Histogram | Operation duration in ms (tag: operation) |\n| `unitofwork.savechanges` | Counter | SaveChanges calls (tag: status) |\n| `unitofwork.transactions` | Counter | Transaction operations (tag: type) |\n| `unitofwork.cache.hits` | Counter | Repository cache hits |\n| `unitofwork.cache.misses` | Counter | Repository cache misses |\n| `interceptor.audit.entities` | Counter | Audited entities (tag: state) |\n| `interceptor.idgeneration.generated` | Counter | Generated IDs (tag: key_type) |\n| `events.dispatched` | Counter | Dispatched domain events (tag: event_type) |\n| `events.handler.errors` | Counter | Handler errors (tags: event_type, handler_type) |\n| `events.dispatch.duration` | Histogram | Event dispatch duration in ms (tag: event_type) |\n\nAll metrics use the meter name `FS.EntityFramework.Library` and are compatible with any OpenTelemetry collector (Prometheus, Grafana, Azure Monitor, etc.).\n\n#### Consume with OpenTelemetry\n\n```csharp\nbuilder.Services.AddOpenTelemetry()\n    .WithMetrics(metrics =\u003e\n    {\n        metrics.AddMeter(\"FS.EntityFramework.Library\");\n    });\n```\n\n## 🎯 Best Practices\n\n### Entity Design Guidelines\n\nFollow these guidelines when designing your entities:\n\n```csharp\n// ✅ Good: Well-designed entity\npublic class Product : BaseAuditableEntity\u003cint\u003e, ISoftDelete\n{\n    // Private setters for business logic enforcement\n    public string Name { get; private set; } = string.Empty;\n    public decimal Price { get; private set; }\n    \n    // Public properties for simple data\n    public string Description { get; set; } = string.Empty;\n    \n    // Soft delete properties (automatic)\n    public bool IsDeleted { get; set; }\n    public DateTime? DeletedAt { get; set; }\n    public string? DeletedBy { get; set; }\n    \n    // Factory method for creation\n    public static Product Create(string name, decimal price)\n    {\n        if (string.IsNullOrWhiteSpace(name))\n            throw new ArgumentException(\"Name cannot be empty\", nameof(name));\n        if (price \u003c= 0)\n            throw new ArgumentException(\"Price must be positive\", nameof(price));\n        \n        var product = new Product();\n        product.SetName(name);\n        product.SetPrice(price);\n        \n        // Raise domain event\n        product.AddDomainEvent(new ProductCreatedEvent(product.Id, name, price));\n        \n        return product;\n    }\n    \n    // Business methods with validation\n    public void SetName(string name)\n    {\n        if (string.IsNullOrWhiteSpace(name))\n            throw new ArgumentException(\"Name cannot be empty\", nameof(name));\n        \n        Name = name;\n    }\n    \n    public void SetPrice(decimal price)\n    {\n        if (price \u003c= 0)\n            throw new ArgumentException(\"Price must be positive\", nameof(price));\n        \n        var oldPrice = Price;\n        Price = price;\n        \n        if (oldPrice != price)\n        {\n            AddDomainEvent(new ProductPriceChangedEvent(Id, oldPrice, price));\n        }\n    }\n}\n```\n\n### Service Layer Patterns\n\nImplement clean service layer patterns:\n\n```csharp\n// ✅ Good: Service with proper separation of concerns\npublic class ProductApplicationService\n{\n    private readonly IUnitOfWork _unitOfWork;\n    private readonly ILogger\u003cProductApplicationService\u003e _logger;\n    \n    public ProductApplicationService(\n        IUnitOfWork unitOfWork, \n        ILogger\u003cProductApplicationService\u003e logger)\n    {\n        _unitOfWork = unitOfWork;\n        _logger = logger;\n    }\n    \n    public async Task\u003cProductDto\u003e CreateProductAsync(CreateProductCommand command)\n    {\n        // Input validation\n        if (string.IsNullOrWhiteSpace(command.Name))\n            throw new ArgumentException(\"Product name is required\");\n        \n        var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n        \n        // Business logic\n        var product = Product.Create(command.Name, command.Price);\n        \n        // Persistence\n        await repository.AddAsync(product);\n        await _unitOfWork.SaveChangesAsync(); // Domain events dispatched here\n        \n        _logger.LogInformation(\"Created product {ProductId}: {ProductName}\", \n            product.Id, product.Name);\n        \n        // Return DTO\n        return new ProductDto(product.Id, product.Name, product.Price);\n    }\n}\n```\n\n\n\n## 🔧 Troubleshooting\n\n### Common Issues and Solutions\n\n#### Issue: Domain Events Not Being Dispatched\n\n**Problem:** Domain events are not being handled even though handlers are registered.\n\n**Solution:** Ensure you're using the domain unit of work or have properly configured event dispatching:\n\n```csharp\n// ❌ Wrong: Using regular SaveChanges\nawait _unitOfWork.SaveChangesAsync(); // Events might not be dispatched\n\n// ✅ Correct: Ensure domain events are configured\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithDomainEvents()\n        .UsingDefaultDispatcher()\n        .WithAutoHandlerDiscovery()\n    .Complete()\n    .Build();\n```\n\n#### Issue: Soft Delete Not Working\n\n**Problem:** Entities are being hard deleted instead of soft deleted.\n\n**Solution:** Ensure entity implements `ISoftDelete` and soft delete is configured:\n\n```csharp\n// ✅ Entity must implement ISoftDelete\npublic class Product : BaseAuditableEntity\u003cint\u003e, ISoftDelete\n{\n    // ISoftDelete properties\n    public bool IsDeleted { get; set; }\n    public DateTime? DeletedAt { get; set; }\n    public string? DeletedBy { get; set; }\n}\n\n// ✅ Configure soft delete\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithSoftDelete()\n    .Build();\n```\n\n#### Issue: Audit Properties Not Being Set\n\n**Problem:** `CreatedAt`, `CreatedBy`, etc., are not being populated automatically.\n\n**Solution:** Ensure audit configuration is properly set up:\n\n```csharp\n// ✅ Configure audit with user provider\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .WithAudit()\n        .UsingHttpContext() // or another user provider\n    .Build();\n```\n\n#### Issue: Repository Not Found\n\n**Problem:** `InvalidOperationException` when trying to get a repository.\n\n**Solution:** Ensure your DbContext is properly registered before adding FS.EntityFramework:\n\n```csharp\n// ✅ Register DbContext first\nservices.AddDbContext\u003cApplicationDbContext\u003e(options =\u003e\n    options.UseSqlServer(connectionString));\n\n// ✅ Then add FS.EntityFramework\nservices.AddFSEntityFramework\u003cApplicationDbContext\u003e()\n    .Build();\n```\n\n### Performance Optimization Tips\n\n#### Use Projections for Read-Only Data\n\n```csharp\n// ✅ Use built-in projection methods for better performance (v10.0.2+)\npublic async Task\u003cIReadOnlyList\u003cProductSummaryDto\u003e\u003e GetProductSummariesAsync()\n{\n    var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n\n    // Direct projection method\n    return await repository.GetAllAsync(p =\u003e new ProductSummaryDto\n    {\n        Id = p.Id,\n        Name = p.Name,\n        Price = p.Price\n    });\n}\n\n// ✅ Paginated projection\npublic async Task\u003cIPaginate\u003cProductSummaryDto\u003e\u003e GetPagedProductSummariesAsync(int page, int size)\n{\n    var repository = _unitOfWork.GetRepository\u003cProduct, int\u003e();\n\n    return await repository.GetPagedAsync(\n        selector: p =\u003e new ProductSummaryDto { Id = p.Id, Name = p.Name, Price = p.Price },\n        pageIndex: page,\n        pageSize: size,\n        orderBy: q =\u003e q.OrderBy(p =\u003e p.Name));\n}\n```\n\n#### Disable Tracking for Read-Only Operations\n\n```csharp\n// ✅ Disable tracking for read-only queries\nvar products = await repository.GetQueryable(disableTracking: true)\n    .Where(p =\u003e p.Price \u003e 100)\n    .ToListAsync();\n```\n\n#### Use Bulk Operations for Large Data Sets\n\n```csharp\n// ✅ Use bulk operations for better performance\nawait repository.BulkInsertAsync(products, saveChanges: true);\n```\n\n## 🤝 Contributing\n\nWe welcome contributions! This project is open source and benefits from community involvement.\n\n### Areas for Contribution\n\n- 🏛️ **Enhanced DDD patterns** (Saga patterns, Event Sourcing support)\n- 🔌 **Additional domain event dispatchers** (Mass Transit, NServiceBus, etc.)\n- ⚡ **Performance optimizations** for aggregate loading and persistence\n- 📋 **Advanced specification implementations**\n- 📚 **Documentation and examples**\n- 🧪 **Test coverage improvements**\n- 🔑 **New ID generation strategies**\n- 🎯 **Domain modeling tools and utilities**\n\n### Code Style\n\n- Use **meaningful domain language** in code\n- Follow **DDD naming conventions**\n- Add **XML documentation** for public APIs\n- Include **unit tests** for domain logic\n- Follow **SOLID principles** and **DDD patterns**\n\n---\n\n## 📄 License\n\nThis project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.\n\n---\n\n## 🌟 Acknowledgments\n\n- Thanks to all contributors who have helped make this library better\n- Inspired by **Domain-Driven Design** principles by Eric Evans\n- Built on top of the excellent **Entity Framework Core**\n- Special thanks to the .NET community for continuous feedback and support\n\n---\n\n## 📞 Support\n\nIf you encounter any issues or have questions:\n\n1. Check the [troubleshooting section](#-troubleshooting)\n2. Search existing [GitHub issues](https://github.com/furkansarikaya/FS.EntityFramework.Library/issues)\n3. Create a new issue with detailed information\n4. Join our community discussions\n\n**Happy Domain Modeling! 🏛️**\n\n---\n\n**Made with ❤️ by [Furkan Sarıkaya](https://github.com/furkansarikaya)**\n\n[![GitHub](https://img.shields.io/badge/github-%23121011.svg?style=for-the-badge\u0026logo=github\u0026logoColor=white)](https://github.com/furkansarikaya)\n[![LinkedIn](https://img.shields.io/badge/linkedin-%230077B5.svg?style=for-the-badge\u0026logo=linkedin\u0026logoColor=white)](https://www.linkedin.com/in/furkansarikaya/)\n[![Medium](https://img.shields.io/badge/medium-%23121011.svg?style=for-the-badge\u0026logo=medium\u0026logoColor=white)](https://medium.com/@furkansarikaya)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffurkansarikaya%2Ffs.entityframework.library","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffurkansarikaya%2Ffs.entityframework.library","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffurkansarikaya%2Ffs.entityframework.library/lists"}