Skip to content

mrdevrobot/Community-LiteDb-AOT

Repository files navigation

Community.LiteDB.Aot

AOT-compatible wrapper for LiteDB - Use LiteDB with Native AOT compilation and Clean Architecture

License: MIT NuGet

🎯 Overview

Community.LiteDB.Aot is a thin, AOT-compatible layer on top of LiteDB that enables:

  • ⚑ Native AOT compilation - Full support for .NET 8 Native AOT
  • πŸ—οΈ Clean Architecture - Zero dependencies in domain entities
  • 🎨 EF Core-style API - Familiar DbContext pattern
  • πŸ’Ύ Same database format - Compatible with standard LiteDB files
  • πŸ”„ Progressive migration - Use alongside existing LiteDB code
  • πŸš€ Source Generators - Compile-time mapper generation with Expression Trees
  • 🎯 DDD Support - Value Objects, Strongly-Typed IDs, Private Setters
  • 🏷️ Data Annotations - [Key], [Required], [MaxLength], [Range] support

✨ Key Features

1. Native AOT Compilation

Full support for .NET 8 Native AOT with automatic trimming of reflection-based code (~30-40% size reduction).

2. Clean Architecture Support

Your domain entities stay pure - zero infrastructure dependencies:

// Clean domain entity
public class Order
{
    public int OrderId { get; set; }
    public decimal Total { get; set; }
    public DateTime CreatedAt { get; set; }
}

3. Source Generator with Expression Trees

Compile-time mapper generation using Expression Trees for:

  • βœ… Private setters support (DDD Value Objects)
  • βœ… Complex nested objects (3+ levels deep)
  • βœ… Collections of nested objects (List)
  • βœ… Near-native performance (compiled delegates)
  • βœ… Full AOT compatibility (no runtime reflection)

4. Strongly-Typed IDs (DDD Value Objects)

Support for strongly-typed IDs to avoid primitive obsession:

public class OrderId
{
    public Guid Value { get; private set; }
    
    public OrderId(Guid value) => Value = value;
    public static OrderId NewId() => new(Guid.NewGuid());
}

public class Order
{
    public OrderId Id { get; private set; } = OrderId.NewId();
    public string CustomerName { get; set; }
    // ...
}

5. Data Annotations Support

Full support for standard Data Annotations attributes:

using System.ComponentModel.DataAnnotations;

public class UserProfile
{
    [Key]
    public int UserId { get; set; }
    
    [Required]
    [MaxLength(100)]
    public string Username { get; set; }
    
    [Range(18, 120)]
    public int Age { get; set; }
}

Supported attributes:

  • [Key] - Primary key detection (auto or manual)
  • [Required] - Not null validation
  • [MaxLength] - String length validation
  • [Range] - Numeric range validation

6. Complex Nested Objects

Support for deeply nested objects and collections:

public class Company
{
    public int Id { get; set; }
    public string Name { get; set; }
    
    // List of nested objects
    public List<Address> Offices { get; set; } = new();
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public Location Coordinates { get; set; }  // 2nd level nesting
}

7. DDD Value Objects with Private Setters

Full support for immutable Value Objects:

public class Money
{
    public decimal Amount { get; private set; }
    public string Currency { get; private set; }
    
    public Money(decimal amount, string currency)
    {
        Amount = amount;
        Currency = currency;
    }
}

public class Product
{
    public int Id { get; set; }
    public Money Price { get; private set; }
    
    public void SetPrice(Money price) => Price = price;
}

πŸ“¦ Quick Start

Installation

dotnet add package Community.LiteDB.Aot
dotnet add package Community.LiteDB.Aot.SourceGenerators

Basic Usage

// 1. Domain Entity (Clean - no dependencies)
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
}

// 2. DbContext (Infrastructure layer)
public partial class AppDbContext : LiteDbContext
{
    public AotLiteCollection<Customer> Customers => Collection<Customer>();
    
    public AppDbContext(string filename) : base(filename) { }
    
    protected override void OnModelCreating(EntityModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>(entity =>
        {
            entity.HasKey(x => x.Id).AutoIncrement();
            entity.Property(x => x.Email).HasIndex().IsUnique();
            entity.Property(x => x.Name).IsRequired().HasMaxLength(100);
        });
    }
}

// 3. Usage
using var db = new AppDbContext("myapp.db");

// Insert
var customer = new Customer { Name = "John", Email = "john@example.com", Age = 30 };
db.Customers.Insert(customer);

// Query
var adults = db.Customers.FindAll().Where(c => c.Age >= 18).ToList();
var john = db.Customers.FindById(new BsonValue(1));

// Update
customer.Age = 31;
db.Customers.Update(customer);

// Delete
db.Customers.Delete(new BsonValue(1));

πŸ—οΈ Architecture

+-------------------------------------+
|  Your Application (AOT-published)  |
+-------------------------------------+
|  Community.LiteDB.Aot (NEW)        |  <- Thin wrapper
|  - LiteDbContext                   |  <- Configuration API
|  - AotLiteCollection<T>            |  <- Type-safe collections
+-------------------------------------+
|  Source Generator (Compile-time)   |  <- Expression Trees
|  - IEntityMapper<T>                |  <- BsonDocument <-> T
|  - Expression Trees for setters    |  <- Private setters support
+-------------------------------------+
|  LiteDB 5.0 (UNCHANGED)            |  <- Core engine
|  + Engine.* (kept by trimmer)      |
|  + Document.* (kept by trimmer)    |
|  - Client.Mapper.* (TRIMMED)       |  <- Reflection removed!
+-------------------------------------+

Key benefit: The AOT trimmer automatically removes unused reflection-based parts of LiteDB (~30-40% size reduction)

πŸ“š Advanced Examples

Using [Key] Attribute

using System.ComponentModel.DataAnnotations;

public class Product
{
    [Key]  // <- Source generator automatically detects this
    public int ProductId { get; set; }
    
    public string Name { get; set; }
    public decimal Price { get; set; }
}

// DbContext - NO configuration needed for [Key]!
public partial class AppDbContext : LiteDbContext
{
    public AotLiteCollection<Product> Products => Collection<Product>();
    
    protected override void OnModelCreating(EntityModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>(entity =>
        {
            entity.ToCollection("products");
        });
    }
}

Transactions

db.BeginTrans();
try
{
    db.Customers.Insert(customer);
    db.Orders.Insert(order);
    db.Commit();
}
catch
{
    db.Rollback();
    throw;
}

Indexes and Constraints

modelBuilder.Entity<Customer>(entity =>
{
    entity.Property(x => x.Email)
          .HasIndex("idx_email")
          .IsUnique();
    
    entity.Property(x => x.City)
          .HasIndex("idx_city");
    
    entity.Property(x => x.Name)
          .IsRequired()
          .HasMaxLength(100);
});

πŸ”„ Migration from Standard LiteDB

Gradual Migration

You can use both packages in the same application:

// Old code (reflection-based)
var oldDb = new LiteDatabase("app.db");
var customersOld = oldDb.GetCollection<Customer>();

// New code (AOT-compatible)
var newDb = new AppDbContext("app.db");
var customersNew = newDb.Customers;

// Both access THE SAME database file!

Migration Steps

  1. Install Community.LiteDB.Aot (keep LiteDB installed)
  2. Create your DbContext class
  3. Migrate repositories one at a time
  4. Remove old LiteDB code when done

πŸ“¦ Package Structure

Community.LiteDB.Aot

Runtime package (~50 KB)

  • Core interfaces and collections
  • LiteDbContext base class
  • AotLiteCollection<T> wrapper
  • Depends on LiteDB >= 5.0.21

Community.LiteDB.Aot.SourceGenerators

Compile-time source generator

  • Automatic IEntityMapper<T> generation
  • Expression Trees for property setters
  • Support for private setters and nested objects
  • [Key] attribute detection
  • Data Annotations validation

πŸ§ͺ Testing

The project includes comprehensive test suites:

  • KeyAttributeTests - [Key] attribute detection and auto-increment
  • PrivateSetterTests - DDD Value Objects with private setters
  • ValueObjectIdTests - Strongly-typed IDs (OrderId, CustomerId, etc.)
  • NestedObjectTests - Complex nested objects and collections
  • DataAnnotationsTests - Validation attributes support

Run tests:

dotnet test

πŸ“Š Benchmarks

Community.LiteDB.Aot is 2-4x faster than standard LiteDB!

Scenario Speedup Details
Simple Entities 2.3-3.5x Object initializers
DDD Value Objects 1.4-3.2x Expression Trees for private setters
Complex Nested 2.4-3.8x Recursive mappers

πŸ‘‰ Full benchmark results: BENCHMARK_RESULTS.md

Run benchmarks yourself:

cd Community.LiteDB.Aot.Benchmarks
dotnet run -c Release

Expected results:

  • Expression Trees - Near-native performance for property access
  • Compiled delegates - 100-1000x faster than reflection
  • AOT trimming - 30-40% smaller executable size

🀝 Contributing

Contributions are welcome! Please open issues or pull requests on GitHub.

πŸ“„ License

This project is licensed under the MIT License.

πŸ”— Links

πŸ™ Credits

Built on top of the excellent LiteDB project by Mauricio David.


Made with ❀️ by MrDevRobot

About

LiteDb Plugin for supporting AOT via Source Generators

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages