ActiveForge.Core
1.0.0
dotnet add package ActiveForge.Core --version 1.0.0
NuGet\Install-Package ActiveForge.Core -Version 1.0.0
<PackageReference Include="ActiveForge.Core" Version="1.0.0" />
<PackageVersion Include="ActiveForge.Core" Version="1.0.0" />
<PackageReference Include="ActiveForge.Core" />
paket add ActiveForge.Core --version 1.0.0
#r "nuget: ActiveForge.Core, 1.0.0"
#:package ActiveForge.Core@1.0.0
#addin nuget:?package=ActiveForge.Core&version=1.0.0
#tool nuget:?package=ActiveForge.Core&version=1.0.0
A lightweight, Active Record-style ORM for .NET with first-class support for SQL Server, PostgreSQL, and MongoDB.
Packages
All connection types live in the ActiveForge namespace, so a single using ActiveForge; is sufficient regardless of the provider chosen.
Features
ActiveForge streamlines data-centric development with a cohesive approach to entities, queries, and data management.
🗂 Entities & Mapping
- Active Record pattern
Entities contain both state and persistence logic, removing the need for external repositories. - Type-safe fields
Provides wrappers for types (string, int, decimal, keys, etc.), tracking nullability and state, and handling conversion automatically. - Polymorphic mapping
Maps base types to concrete subtypes at runtime. - Custom field mappers
Easily support non-standard type conversions. - Field encryption
Simple attribute-based encryption/decryption for sensitive data.
🔍 Querying
- Composable predicates
Build queries with terms for equality, containment, ranges, null checks, and pattern matching; combine them with logical operators. - LINQ support
Write queries using familiar C# syntax, auto-translated to efficient ORM operations. - Pagination
Built-in paging with metadata for efficient handling of large datasets. - Lazy streaming
Stream results row-by-row for memory efficiency. - Field subsets
Load or update only the fields you need.
💾 Data Management
- Transactions
Explicit and nested transaction support; control scope via code or attributes. - Unit of Work
Integrated pattern for grouping multiple changes; supports both code-based and attribute-based usage. - Connection lifecycle
Connections and transactions are managed automatically on every write, ensuring reliability. - Batch operations
Queue up changes and execute them in bulk to reduce database round-trips.
🌐 Dependency Injection & Service Proxy
- Auto-discovery & registration
Services marked with a simple interface are discovered and registered automatically. - Fluent builder API
Register all or selected services with fine-grained control. - Seamless DI integration
Simplifies service composition, testing, and enables proxy/interceptor scenarios.
Quick Start
1. Connect (standalone)
using ActiveForge;
// SQL Server
var conn = new SqlServerConnection(
"Server=.;Database=Demo;Integrated Security=True;TrustServerCertificate=True;");
// PostgreSQL
var conn = new PostgreSQLConnection(
"Host=localhost;Database=demo;Username=app;Password=secret;");
// MongoDB
var conn = new MongoDataConnection(
"mongodb://localhost:27017",
"demo");
// SQLite
var conn = new SQLiteConnection("Data Source=app.db");
conn.Connect();
2. Register with DI
Works in any DI host — ASP.NET Core, Worker Service, console, etc.
The provider-specific AddActiveForge* call registers the connection + UoW and returns an IActiveForgeBuilder.
Chain .AddServices() to auto-scan your assembly for IService implementations.
// Program.cs — choose one provider, then scan for IService implementations:
builder.Services
.AddActiveForgeSqlServer(
"Server=.;Database=Demo;Integrated Security=True;TrustServerCertificate=True;")
.AddServices(typeof(Program).Assembly);
builder.Services
.AddActiveForgePostgreSQL("Host=localhost;Database=demo;Username=app;Password=secret;")
.AddServices(typeof(Program).Assembly);
builder.Services
.AddActiveForgeMongoDB("mongodb://localhost:27017", "demo")
.AddServices(typeof(Program).Assembly);
builder.Services
.AddActiveForgeSQLite("Data Source=app.db")
.AddServices(typeof(Program).Assembly);
3. Define entities
Entity classes are provider-agnostic — the same class works with SQL Server, PostgreSQL, MongoDB, and SQLite.
using ActiveForge;
using ActiveForge.Attributes;
[Table("categories")]
public class Category : IdentityRecord
{
[Column("name")] public TString Name = new TString();
public Category() { }
public Category(DataConnection conn) : base(conn) { }
}
[Table("products")]
public class Product : IdentityRecord
{
[Column("name")] public TString Name = new TString();
[Column("price")] public TDecimal Price = new TDecimal();
[Column("in_stock")]
[DefaultValue(true)] public TBool InStock = new TBool();
[Column("created_at")]
[ReadOnly] public TDateTime CreatedAt = new TDateTime();
[Column("notes")]
[NoPreload] public TString Notes = new TString();
[Column("CategoryID")] public TForeignKey CategoryID = new TForeignKey();
// Embedded Record — triggers automatic INNER JOIN in queries
public Category Category;
public Product() { Category = new Category(); }
public Product(DataConnection conn) : base(conn) { Category = new Category(conn); }
}
Naming conventions: PostgreSQL folds unquoted identifiers to lower-case — use lower-case
[Table]and[Column]values. MongoDB uses the attribute values as BSON field and collection names verbatim.Key attributes:
[ReadOnly]— included in SELECT but never written.[NoPreload]— excluded from the default SELECT; include viaFieldSubset.[DefaultValue]— pre-populates the field on construction.[Sensitive]— masks values in diagnostic output.[Encrypted]— transparent encrypt/decrypt at ORM layer.
4. CRUD
using ActiveForge.Query;
using ActiveForge.Linq;
// ── INSERT ────────────────────────────────────────────────────────────────────
var p = new Product(conn);
p.Name.SetValue("Widget");
p.Price.SetValue(9.99m);
p.InStock.SetValue(true);
p.Insert(); // p.ID is populated automatically after insert
// ── READ by primary key ───────────────────────────────────────────────────────
var p2 = new Product(conn);
p2.ID.SetValue(1);
p2.Read(); // throws PersistenceException if not found
// ── QUERY (QueryTerm API) ─────────────────────────────────────────────────────
var template = new Product(conn);
var inStock = new EqualTerm(template, template.InStock, true);
var byName = new OrderAscending(template, template.Name);
var results = conn.QueryAll(template, inStock, byName, 0, null);
// ── QUERY (LINQ) ──────────────────────────────────────────────────────────────
List<Product> page = conn.Query(new Product(conn))
.Where(x => x.InStock == true && x.Price < 50m)
.OrderBy(x => x.Name)
.Skip(0).Take(20)
.ToList();
// ── QUERY with JOIN filter ────────────────────────────────────────────────────
List<Product> electronics = conn.Query(new Product(conn))
.Where(x => x.Category.Name == "Electronics")
.OrderBy(x => x.Price)
.ToList();
// ── UPDATE ────────────────────────────────────────────────────────────────────
p.Price.SetValue(14.99m);
p.Update(RecordLock.UpdateOption.IgnoreLock); // update all columns
p.Notes.SetValue("On sale");
p.UpdateChanged(); // update only changed columns
// ── DELETE ────────────────────────────────────────────────────────────────────
p.Delete(); // delete by PK
// Delete by predicate:
var disc = new EqualTerm(template, template.InStock, false);
template.Delete(disc);
5. Service proxy — automatic connection & transaction management
Implement IService on your class alongside a service interface. Castle DynamicProxy handles
open → begin → commit → close with no virtual methods or framework coupling required.
using ActiveForge;
using ActiveForge.Transactions;
// ── Interface (consumed by controllers / other services)
public interface IOrderService
{
Order GetById(int id);
void Ship(int orderId);
}
// ── Implementation — IService triggers auto-registration
public class OrderService : IOrderService, IService
{
private readonly DataConnection _conn;
public OrderService(DataConnection conn) { _conn = conn; }
public Order GetById(int id) { ... }
[Transaction] // opens connection, begins tx, commits/rolls back, closes connection
public void Ship(int orderId)
{
var order = new Order(_conn);
order.ID.SetValue(orderId);
_conn.Read(order);
order.Status.SetValue("Shipped");
order.Update(RecordLock.UpdateOption.IgnoreLock);
// commit on success; rollback + connection close on exception
}
}
// Register — auto-scan picks up OrderService, registers as IOrderService:
builder.Services
.AddActiveForgeSqlServer("Server=...;...")
.AddServices(typeof(Program).Assembly);
// Inject by interface — proxy is transparent:
public class CheckoutController : ControllerBase
{
public CheckoutController(IOrderService orders) { _orders = orders; }
[HttpPost("{id}/ship")]
public IActionResult Ship(int id) { _orders.Ship(id); return NoContent(); }
}
Manual usage (standalone, no DI):
var conn = new SqlServerConnection("...");
var uow = new SqlServerUnitOfWork(conn);
var svc = ActiveForgeServiceFactory.Create(new OrderService(conn), conn, uow);
svc.Ship(42);
// Or With.Transaction for ad-hoc work:
With.Transaction(uow, () =>
{
order.Status.SetValue("Shipped");
order.Update(RecordLock.UpdateOption.IgnoreLock);
shipment.Insert();
});
Documentation
| Guide | Description |
|---|---|
| Getting Started | Step-by-step tutorial |
| Field Types | All TField types and their operators |
| Query Builder | Composing WHERE, ORDER BY, and pagination |
| Transactions & DI | Manual transactions, IUnitOfWork, With.Transaction, [Transaction] interceptor, DI service proxies |
| LINQ Querying | conn.Query<T>() LINQ support |
| Field Subsets | Partial fetches and partial updates |
| Advanced | Encryption, custom mappers, polymorphism |
| Wiki | Comprehensive reference — all concepts with examples |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.7.2
- Castle.Core (>= 5.1.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
.NETStandard 2.0
- Castle.Core (>= 5.1.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
.NETStandard 2.1
- Castle.Core (>= 5.1.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net10.0
- Castle.Core (>= 5.1.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net8.0
- Castle.Core (>= 5.1.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
-
net9.0
- Castle.Core (>= 5.1.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on ActiveForge.Core:
| Package | Downloads |
|---|---|
|
ActiveForge.SQLite
Provides SQLite adapter for ActiveForge ORM. Provides type-safe fields, composable query predicates, LINQ query translation, nested transactions, Unit of Work and DI auto-scan. |
|
|
ActiveForge.MongoDB
Provides MongoDB adapter for ActiveForge ORM. Provides type-safe fields, composable query predicates, LINQ query translation, nested transactions, Unit of Work and DI auto-scan. |
|
|
ActiveForge.SqlServer
Provides SQL Server adapter for ActiveForge ORM. Provides type-safe fields, composable query predicates, LINQ query translation, nested transactions, Unit of Work and DI auto-scan. |
|
|
ActiveForge.PostgreSQL
Provides PostgreSQL adapter for ActiveForge ORM. Provides type-safe fields, composable query predicates, LINQ query translation, nested transactions, Unit of Work and DI auto-scan. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 37 | 3/13/2026 |
### v1.0.0 Highlights
- Active Record pattern — entities contain both state and persistence logic
- 25+ type-safe field types with nullability tracking and automatic conversion
- Composable predicates (equality, containment, ranges, null checks, pattern matching)
- Full LINQ query support with auto-translation to ORM operations
- Built-in pagination with metadata and lazy streaming for memory efficiency
- Explicit and nested transaction support with `[Transaction]` attribute interception
- Unit of Work pattern for grouping multiple changes
- Batch operations for reducing database round-trips
- Field encryption via `[Encrypted]` attribute
- Polymorphic mapping and custom field mappers
- DI auto-discovery and fluent builder API