Introducing Funcular ORM: A Speedy, Lambda-Powered Micro-ORM for .NET and MSSQL

Well, folks, we’ve done it—we’ve just pushed Funcular ORM to NuGet.org as version 0.9.2, our first non-prerelease edition; you can grab it right here. If you’re like us at Funcular Labs—with decades under our belts wrangling .NET databases, from the early ADO days to modern microservices—you know how frustrating it can be when your ORM gets in the way rather than speeding you along. That’s why we built this: a lightweight, no-frills micro-ORM tailored for MSSQL that lets you query with familiar C# lambdas, skips the heavy configuration, and delivers performance that punches above its weight. Think of it as the tool we wish we’d had back when we were consulting on those tight-deadline projects… efficient, secure, and ready to roll without the bloat.
At Funcular Labs, we’re all about solving real business problems with tech that fits, scales, and lasts—whether that’s custom software, AI integrations, or rescuing projects gone off the rails. Funcular ORM fits right into that ethos; it’s designed for developers who need to move fast, query smart, and avoid the pitfalls of over-engineered solutions. No DbContexts, no entity models, no endless annotations—just define your classes, connect, and go. And with benchmarks showing it handling 10,000 rows in under 60 milliseconds, or inserts at 3,000–4,000 per second, it’s got the speed to back up the simplicity.
Why Choose Funcular ORM Over the Usual Suspects?
We’ve all been there: sifting through StackOverflow threads, debating between heavyweights like Entity Framework Core (EF Core) or NHibernate, and lighter options like Dapper, NPoco, or PetaPoco. Each has its place, sure—but if you’re tired of writing raw SQL (hello, Dapper), wrestling with configurations (looking at you, NHibernate), or dealing with performance overhead (EF Core, we’re talking about those abstractions), Funcular ORM offers a fresh alternative. It’s a micro-ORM that supports lambda expressions out of the box for queries, making your code strongly typed and intuitive, while keeping things lean and fast.
Let’s break it down with some side-by-side comparisons; we’ll use a simple Person entity (with properties like Id, FirstName, LastName, Birthdate, and Gender) against a MSSQL table named persons. Assume we’ve got a connection string ready, and we’re focusing on common operations: inserts, retrieves, updates, and queries with predicates, operators, ordering, paging, and aggregates. We’ll highlight where Funcular shines—especially in ease of use without sacrificing control.
Setup: Minimalism Wins
In Funcular ORM, you skip the ceremony; no contexts or models required. Just instantiate the provider:
using Funcular.Data.Orm.SqlServer; var connectionString = "Data Source=localhost;Initial Catalog=funky_db;Integrated Security=SSPI;TrustServerCertificate=true;"; var provider = new SqlServerOrmDataProvider(connectionString) { Log = s => Console.WriteLine(s) // Optional, for peeking at generated SQL };
Compare that to EF Core, where you define a DbContext, map entities (often with annotations or fluent config), and handle migrations:
public class PersonContext : DbContext { public DbSet Persons { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(connectionString); } }
NHibernate demands session factories and mappings—XML or fluent—which can balloon quickly. Dapper? It’s extension methods on IDbConnection, so setup is light, but you write SQL strings everywhere. NPoco and PetaPoco are similar to Dapper: simple connections, but again, SQL-heavy. Funcular’s edge? Lambda support without the full ORM tax, and conventions handle PKs (like id or person_id) and mappings automatically—ignoring case and underscores—so you rarely need attributes like [Key] or [Column].
Inserting: Speed and Simplicity
With Funcular, inserts are straightforward, handling identities automatically:
var person = new Person { FirstName = "Jane", LastName = "Smith", Birthdate = DateTime.Today.AddYears(-28), Gender = "Female" }; provider.Insert(person); // person.Id now has the new value
Dapper requires SQL:
connection.Execute("INSERT INTO persons (FirstName, LastName, Birthdate, Gender) VALUES (@FirstName, @LastName, @Birthdate, @Gender)", person);.
EF Core:
context.Persons.Add(person); context.SaveChanges();
—but with change tracking overhead. NHibernate needs a session, after mapping setup:
session.Save(person);
(NPoco/PetaPoco offer POCO inserts like db.Insert(person);, which is closer.)
Retrieving: By ID or List
// Grab one: var retrieved = provider.Get(person.Id);. // Or all: var allPersons = provider.GetList().ToList();. // Dapper: connection.QuerySingle("SELECT * FROM persons WHERE id = @Id", new { Id = person.Id });. // EF Core: context.Persons.Find(person.Id); /* or */ context.Persons.ToList();. // NHibernate: session.Get(person.Id);. // NPoco: db.SingleById(person.Id);.
Funcular matches the lightness of micro-ORMs like NPoco but adds lambda querying seamlessly—no SQL and no property name literals or value literals required.
Updating: Targeted and Safe
Funcular updates by PK: retrieved.FirstName = "Janet"; provider.Update(retrieved);
Dapper: Write your UPDATE SQL. EF Core tracks changes automatically but can be heavier. NHibernate: Similar to EF, with sessions. PetaPoco/NPoco: db.Update(person);. Here, Funcular’s parameterized queries ensure security, and its minimalism avoids the tracking bloat of full ORMs—updates clock in at 0.5–0.6 ms per row in our tests.
Querying with Predicates and Operators: Where Lambdas Shine
This is where Funcular pulls ahead for many of us; use C# lambdas for WHERE clauses, supporting =, <>, >, >=, <, <=, LIKE (via StartsWith/EndsWith/Contains), AND, OR, IN, IS NULL, IS NOT NULL—all translated to parameterized SQL.
var does = provider.Query() .Where(p => p.LastName == "Doe" && p.Gender == "Male") .ToList();
For date operators (no Age property, but we can filter ranges on Birthdate):
var fromDate = DateTime.Today.AddYears(-35); var toDate = DateTime.Today.AddYears(-25); var midThirties = provider.Query() .Where(p => p.Birthdate >= fromDate && p.Birthdate <= toDate) .ToList(); // Folks born 25–35 years ago Or ORs and nulls: .Where(p => p.Birthdate == null || p.Birthdate < DateTime.Today.AddYears(-50));. // String ops: .Where(p => p.LastName.StartsWith("Sm") && p.FirstName.Contains("an"));. // Collections for IN: var names = new[] { "Doe", "Smith" }; .Where(p => names.Contains(p.LastName));.
Dapper? You write the SQL:
"WHERE LastName = @LastName AND Gender = @Gender" // No lambdas—error-prone for complex predicates.
EF Core and NHibernate support LINQ/lambdas, but with more setup and potential for inefficient queries (N+1 issues). NPoco/PetaPoco lean on SQL or basic builders, lacking full lambda translation. Funcular gives you lambda ease without the full ORM complexity—perfect if you want strongly-typed filters but control over SQL generation.
Ordering, Paging, and Aggregates: Built-In and Efficient
// Ordering: .OrderBy(p => p.LastName).ThenByDescending(p => p.Birthdate);. // Paging: .Skip(10).Take(5); //—uses efficient OFFSET/FETCH. // Aggregates: var countMales = provider.Query().Count(p => p.Gender == "Male"); // or .Max(p => p.Birthdate);, .Any(p => p.LastName == "Doe");, .All(p => p.Birthdate != null);.
All competitors—EF/NHibernate via LINQ, Dapper/NPoco/PetaPoco—handle these via SQL. But Funcular makes them lambda-simple without contexts or heavy abstractions; no workarounds needed, and performance stays crisp since we cache reflection and parameterize everything.
Transactions: Atomic Operations Made Easy
// Wrap multiples: provider.BeginTransaction(); // inserts/updates provider.CommitTransaction(); // or rollback.
Straightforward, like ADO, but with our lambda perks.
To the credit of EF/NHibernate, they do have built-in transaction support via contexts/sessions. Dapper uses Transaction on connections. Similar across the board, but Funcular keeps it light.
What Funcular Doesn’t Do (Yet)—And Why That’s Okay
We focused on the 80%—no joins, no bulk ops, no deletes (for now, to protect your data). If you need those, stick with EF for relationships or Dapper for raw power. But for straightforward CRUD with lambdas? We’re your speedy ally. And unlike some micro-ORMs, we ignore unmatched properties/columns by default—no [NotMapped] required unless you want it.
So, why try Funcular ORM? Because we’ve been in the trenches for 30+ years, and we know you want tools that empower rather than encumber. Download it from NuGet, spin up the quickstart database from our repo (schema and mock data generation scripts included), and run those unit tests—you’ll be querying in minutes. We’re eager for beta testers to push it further; share your feedback on features like bulk updates or deletes. And if you’re a contributor at heart, join us on GitHub—we’d love your pull requests to make this even better. Let’s build something great together at Funcular Labs…