Dtde.EntityFramework 1.0.0

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

<div align="center">

DTDE - Distributed Temporal Data Engine

Transparent horizontal sharding and temporal versioning for Entity Framework Core

.NET EF Core License Tests GitHub

πŸ“š Documentation Β· πŸš€ Quick Start Β· πŸ’‘ Samples Β· πŸ“Š Benchmarks

</div>


Overview

DTDE is a NuGet package that adds transparent horizontal sharding and optional temporal versioning to Entity Framework Core applications. Write standard LINQ queries β€” DTDE handles data distribution, query routing, and result merging automatically.

// Standard EF Core LINQ - DTDE routes queries transparently
var euCustomers = await db.Customers
    .Where(c => c.Region == "EU")
    .ToListAsync();  // Automatically queries only EU shard

// Point-in-time queries for temporal entities
var ordersLastMonth = await db.ValidAt<Order>(DateTime.Today.AddMonths(-1))
    .Where(o => o.Status == "Completed")
    .ToListAsync();

✨ Key Features

Feature Description
πŸ”€ Transparent Sharding Distribute data across tables or databases invisibly
⏱️ Temporal Versioning Track entity history with point-in-time queries
🎯 Property Agnostic Use ANY property names for sharding keys and temporal boundaries
πŸ“ EF Core Native Works with standard LINQ β€” no special query syntax required
⚑ Multiple Strategies Date-based, hash-based, range-based, or composite sharding
πŸ—„οΈ Hot/Warm/Cold Tiers Support for data tiering across storage tiers
βœ… Fully Tested 100+ unit and integration tests

πŸ“¦ Installation

# All-in-one package (recommended)
dotnet add package Dtde.EntityFramework

# Or install individual packages
dotnet add package Dtde.Abstractions  # Core interfaces
dotnet add package Dtde.Core          # Core implementations
dotnet add package Dtde.EntityFramework  # EF Core integration

Requirements: .NET 8.0+ / 9.0+ / 10.0+, Entity Framework Core 8.0+ / 9.0+ / 10.0+


πŸš€ Quick Start

1. Define Your Entity

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public string Region { get; set; } = string.Empty;  // Shard key
    public DateTime CreatedAt { get; set; }
}

2. Create Your DbContext

public class AppDbContext : DtdeDbContext
{
    public DbSet<Customer> Customers => Set<Customer>();

    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Customer>(entity =>
        {
            entity.ShardBy(c => c.Region);  // Enable sharding by Region
        });
    }
}

3. Configure Services

builder.Services.AddDbContext<AppDbContext>(options =>
{
    options.UseSqlServer(connectionString);
    options.UseDtde(dtde =>
    {
        dtde.AddShard(s => s.WithId("EU").WithShardKeyValue("EU").WithTier(ShardTier.Hot));
        dtde.AddShard(s => s.WithId("US").WithShardKeyValue("US").WithTier(ShardTier.Hot));
        dtde.AddShard(s => s.WithId("APAC").WithShardKeyValue("APAC").WithTier(ShardTier.Hot));
    });
});

4. Use It!

// Queries are automatically routed to correct shard(s)
var allCustomers = await _context.Customers.ToListAsync();  // Queries all shards
var euCustomers = await _context.Customers
    .Where(c => c.Region == "EU")
    .ToListAsync();  // Only queries EU shard

// Inserts are automatically routed based on shard key
_context.Customers.Add(new Customer { Name = "Acme Corp", Region = "US" });  // Routes to US shard
await _context.SaveChangesAsync();

πŸ”€ Sharding Strategies

DTDE supports multiple sharding strategies to match your data access patterns:

Property-Based Sharding

Distribute data by a property value (region, tenant, category):

modelBuilder.Entity<Customer>(entity =>
{
    entity.ShardBy(c => c.Region);
});

Use cases: Multi-region deployments, GDPR compliance, data residency

Date-Based Sharding

Partition data by date for time-series workloads:

modelBuilder.Entity<Transaction>(entity =>
{
    entity.ShardByDate(t => t.TransactionDate, DateInterval.Month);
});

Use cases: Financial transactions, audit logs, metrics, event sourcing

Hash-Based Sharding

Even distribution across shards using consistent hashing:

modelBuilder.Entity<UserProfile>(entity =>
{
    entity.ShardByHash(u => u.UserId, shardCount: 8);
});

Use cases: High-volume data, preventing hotspots, horizontal scaling

Composite Sharding

Combine strategies for complex scenarios:

modelBuilder.Entity<Order>(entity =>
{
    entity.ShardBy(o => o.Region)
          .ThenByDate(o => o.OrderDate);
});

⏱️ Temporal Versioning

Track entity history and query data at any point in time:

Enable Temporal Tracking

modelBuilder.Entity<Contract>(entity =>
{
    entity.HasTemporalValidity(
        validFrom: nameof(Contract.ValidFrom),
        validTo: nameof(Contract.ValidTo));
});

Temporal Queries

// Current data
var current = await _context.ValidAt<Contract>(DateTime.UtcNow).ToListAsync();

// Historical data (as of a specific date)
var historical = await _context.ValidAt<Contract>(new DateTime(2024, 1, 1)).ToListAsync();

// All versions (bypass temporal filtering)
var allVersions = await _context.AllVersions<Contract>()
    .Where(c => c.ContractNumber == "C-001")
    .OrderBy(c => c.ValidFrom)
    .ToListAsync();

// Data within a date range
var rangeData = await _context.ValidBetween<Contract>(startDate, endDate).ToListAsync();

Temporal Operations

// Add with effective date
_context.AddTemporal(contract, effectiveFrom: DateTime.UtcNow);

// Create new version (closes old, opens new)
var newVersion = _context.CreateNewVersion(existing, changes, effectiveDate);

// Terminate (close validity)
_context.Terminate(contract, terminationDate: DateTime.UtcNow);

await _context.SaveChangesAsync();

πŸ”„ Mixed Usage: Sharded + Regular Entities

DTDE works seamlessly alongside regular EF Core entities:

public class AppDbContext : DtdeDbContext
{
    public DbSet<Customer> Customers => Set<Customer>();   // Sharded
    public DbSet<Contract> Contracts => Set<Contract>();   // Temporal
    public DbSet<AuditLog> AuditLogs => Set<AuditLog>();   // Regular EF Core
}
Entity Configuration Behavior
ShardBy() configured Queries routed by shard key
HasTemporalValidity() configured Temporal filtering applied
No special configuration Standard EF Core entity
Direct DbSet<T> access Bypasses DTDE filtering

πŸ—„οΈ Shard Tiers

Organize shards by access frequency for cost optimization:

dtde.AddShard(s => s
    .WithId("2024-current")
    .WithTier(ShardTier.Hot)         // Frequently accessed, recent data
    .WithConnectionString(fastStorage));

dtde.AddShard(s => s
    .WithId("2023-archive")
    .WithTier(ShardTier.Cold)        // Archived, rarely accessed
    .WithConnectionString(cheapStorage)
    .AsReadOnly());                   // Prevent accidental writes
Tier Description Typical Storage
Hot Frequently accessed, recent data SSD, Premium SQL
Warm Less frequently accessed Standard SQL
Cold Archived, rarely accessed Archive storage
Archive Long-term retention Cold storage

βš™οΈ Configuration Options

Fluent API

options.UseDtde(dtde =>
{
    // Entity configuration
    dtde.ConfigureEntity<Order>(e => e.ShardByDate(o => o.OrderDate));

    // Shard definitions
    dtde.AddShard(s => s.WithId("primary").WithConnectionString("..."));

    // Load from configuration file
    dtde.AddShardsFromConfig("shards.json");

    // Default temporal context
    dtde.SetDefaultTemporalContext(() => DateTime.UtcNow);

    // Performance tuning
    dtde.SetMaxParallelShards(10);

    // Diagnostics
    dtde.EnableDiagnostics();
});

JSON Configuration (shards.json)

{
  "shards": [
    {
      "shardId": "2024-q4",
      "name": "Q4 2024 Data",
      "connectionString": "Server=...;Database=Data2024Q4",
      "tier": "Hot",
      "dateRangeStart": "2024-10-01",
      "dateRangeEnd": "2024-12-31",
      "isReadOnly": false,
      "priority": 100
    },
    {
      "shardId": "2024-archive",
      "name": "2024 Archive",
      "connectionString": "Server=...;Database=Archive2024",
      "tier": "Cold",
      "isReadOnly": true,
      "priority": 10
    }
  ]
}

πŸ“Š Performance Benchmarks

Comprehensive benchmarks comparing single table vs sharded approaches:

Test Environment

Component Specification
CPU 12th Gen Intel Core i9-12900H (14 cores, 20 threads)
Runtime .NET 9.0, RyuJIT AVX2
Database SQLite (file-based, separate DBs per benchmark)
Framework BenchmarkDotNet 0.15.0

Key Results

Query Type Records Single Table Sharded Improvement
Point Lookup 100K 143.9 ns 146.5 ns ~Same
Date Range (1 month) 100K 16,103 Β΅s 3,596 Β΅s 4.5x faster
Region Scan 100K 3,659 Β΅s 1,786 Β΅s 2.0x faster
Count 50K 3,534 Β΅s 26.0 Β΅s 136x faster

Key insight: Sharded queries benefit significantly from partition pruning β€” queries that target a specific shard key value only scan relevant partitions.

When to Use Sharding

βœ… Good candidates:

  • Large datasets (millions+ rows)
  • Time-series / temporal data
  • Multi-tenant applications
  • Geographic distribution requirements
  • High write throughput needs
  • Hot/cold data patterns

⚠️ Consider carefully:

  • Small datasets (<100K rows)
  • Random access patterns
  • Complex cross-entity joins
  • Simple CRUD applications
# Run benchmarks
cd benchmarks/Dtde.Benchmarks
dotnet run -c Release

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Your Application                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                   Dtde.EntityFramework                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚DtdeDbContextβ”‚  β”‚Query Engine β”‚  β”‚   Update Engine     β”‚  β”‚
β”‚  β”‚  - ValidAt  β”‚  β”‚ - Rewriter  β”‚  β”‚  - VersionManager   β”‚  β”‚
β”‚  β”‚  - AllVersionsβ”‚ β”‚ - Executor  β”‚  β”‚  - ShardRouter     β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                      Dtde.Core                               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Metadata   β”‚  β”‚  Sharding   β”‚  β”‚     Temporal        β”‚  β”‚
β”‚  β”‚  Registry   β”‚  β”‚  Strategies β”‚  β”‚     Context         β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                   Dtde.Abstractions                          β”‚
β”‚         Interfaces β€’ Contracts β€’ Exceptions                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Project Structure

dtde/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ Dtde.Abstractions/        # Core interfaces and contracts
β”‚   β”œβ”€β”€ Dtde.Core/                # Core implementations
β”‚   └── Dtde.EntityFramework/     # EF Core integration
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ Dtde.Core.Tests/          # Unit tests
β”‚   β”œβ”€β”€ Dtde.EntityFramework.Tests/
β”‚   └── Dtde.Integration.Tests/
β”œβ”€β”€ samples/                       # Sample applications
β”‚   β”œβ”€β”€ Dtde.Sample.WebApi/       # Basic getting started
β”‚   β”œβ”€β”€ Dtde.Samples.RegionSharding/   # Property-based sharding
β”‚   β”œβ”€β”€ Dtde.Samples.DateSharding/     # Date-based sharding
β”‚   β”œβ”€β”€ Dtde.Samples.HashSharding/     # Hash-based sharding
β”‚   β”œβ”€β”€ Dtde.Samples.MultiTenant/      # Multi-tenancy
β”‚   └── Dtde.Samples.Combined/         # Mixed strategies
β”œβ”€β”€ benchmarks/
β”‚   └── Dtde.Benchmarks/          # Performance benchmarks
└── docs/                         # Documentation (MkDocs)

πŸ’‘ Sample Projects

Explore working examples for each sharding strategy:

Sample Strategy Use Case
Dtde.Sample.WebApi Basic Getting started
Dtde.Samples.RegionSharding Property-based Multi-region data residency
Dtde.Samples.DateSharding Date-based Time-series, audit logs
Dtde.Samples.HashSharding Hash-based Even data distribution
Dtde.Samples.MultiTenant Tenant-based SaaS multi-tenancy
Dtde.Samples.Combined Mixed Complex enterprise scenarios

πŸ§ͺ Testing

# Run all tests (101 tests)
dotnet test

# Run with coverage
dotnet test --collect:"XPlat Code Coverage"

# Run specific test project
dotnet test tests/Dtde.Core.Tests/

πŸ“š Documentation


🀝 Contributing

Contributions are welcome! Please read our Contributing Guide before submitting PRs.

# Clone and build
git clone https://github.com/yohasacura/dtde.git
cd dtde
dotnet build
dotnet test

See also:


πŸ“„ License

This project is licensed under the MIT License β€” see the LICENSE file for details.


πŸ™ Acknowledgments


<div align="center">

Made with ❀️ for the .NET community

⭐ Star on GitHub Β· πŸ› Report Bug Β· πŸ’¬ Discussions

</div>

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

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 117 12/12/2025