SqlSugar: a multi-database .NET ORM with cross-database transactions
.NET AOT ORM supporting SQL Server, MySQL, MongoDB, PostgreSQL (including HighGo), DB2, Hana, GaussDB, DuckDB, SQLite, Oracle, Xugu, Dameng, KingbaseES, Shentong, ClickHouse, QuestDB, TDengine, OceanBase and TiDB. Object/Relational Mapping for C# and VB.NET, .NET 8/9.
At a glance
- What is it?
- SqlSugar is an MIT-licensed C# ORM covering MySQL, SQL Server, SQLite, Oracle, PostgreSQL, MongoDB and a long list of Chinese and cloud databases. Its selling point is not entity mapping but one API surface across all of them, including transactions that span two engines at once.
- Who is it for?
- SqlSugar fits teams running the same C# codebase against several engines, or shipping to customers who each bring their own database, because the provider list and the cross-database transaction support are the reason to pick it over a single-engine mapper. It does not fit teams that want one engine, minimal abstraction, and SQL they can read directly in the source, since the query layer builds SQL for you.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- DotNetNext/SqlSugar5,844 ★ · +8
| Repository | 2026-09-23 | 2026-11-14 |
|---|---|---|
| DotNetNext/SqlSugar | 5.8k | 5.8k |
8 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The problem SqlSugar solves: one C# API over many engines
Most .NET ORMs are written for one database and treat the others as an afterthought. SqlSugar inverts that. The README lists MySql, SqlServer, Sqlite, Oracle, postgresql, 达梦, Mongodb, 人大金仓, 神通数据库, 瀚高, Access, DB2, DuckDb, Hana, OceanBase, TDengine, QuestDb, Clickhouse, Huawei GaussDB, GBase, MariaDB, Tidb, Odbc, Percona Server, Amazon Aurora, Azure Database for MySQL and Google Cloud SQL for MySQL, plus a "custom database" escape hatch. That breadth is the product. If you are building a product that ships to customers who each run a different engine, or you are migrating between engines, the value is that the entity classes and most of the query code do not change. The audience is C# and VB.NET developers on .NET Framework through .NET 10, including teams that need domestic Chinese databases that mainstream ORMs do not cover. The trade-off is honest: an abstraction that spans this many engines cannot expose every engine-specific feature, so anything unusual will drop you back to raw SQL.
How the query layer works: fluent expressions compiled to SQL
Queries are built from generic expressions, not string concatenation. The README's first example chains LeftJoin three times, then Where, then Select into a projection type, and shows the SQL that results: a SELECT with three LEFT JOINs and a parameterized WHERE clause ending in @Id0. The lambda parameters are positional, so the third join receives four lambda parameters. That is the whole mechanism: your lambdas become an expression tree, the provider translates it to that engine's dialect, and values become parameters rather than literals.
The same pattern covers paging. ToPageList takes a page index, a page size and a ref totalCount, so the count query and the page query are produced together. Dynamic filters use Expressionable: you loop over a string array, call Or for each item with a Contains call, then pass exp.ToExpression() into Where. The README shows the generated SQL as a pair of LIKE clauses with CAST parameters, which is what you want when the number of filter terms is only known at runtime. Navigation properties are handled by Includes, which the README demonstrates in multi-level form (Provinces to Citys to Street) and also combined with an explicit LeftJoin and Select. If you care about the emitted SQL shape for a specific Includes chain, enable the AOP log hook and read it.
Installing SqlSugar and running a first query
The README links to a wiki page titled NUGET for installation, so the package comes from NuGet. The repository does not pin a version in the README; the recent releases list shows 5.1.4.197 published on 2025-07-06, with 5.1.4.187 before it on 2025-03-29.
The README's singleton example is the recommended shape for application code, because a SqlSugarScope instance carries the connection and the AOP hooks and can be shared across methods. The configuration object takes a DbType, a ConnectionString and IsAutoCloseConnection, and the second argument is a setup action where you attach the logging hook.
public static SqlSugarScope Db = new SqlSugarScope(new ConnectionConfig()
{
DbType = SqlSugar.DbType.SqlServer,
ConnectionString = Config.ConnectionString,
IsAutoCloseConnection = true
},
db => {
db.Aop.OnLogExecuting = (s, p) =>
{
Console.WriteLine(s);
};
});With that in place, a query is a single call. The README's paging example declares the count variable first, because ToPageList fills it by reference.
int pageIndex = 1;
int pageSize = 20;
int totalCount = 0;
var page = db.Queryable<Student>().ToPageList(pageIndex, pageSize, ref totalCount);After the first call, watch the console. The OnLogExecuting hook prints each statement, and that output is the fastest way to confirm which dialect your provider emitted and whether a query became one statement or several.
Cross-database transactions are the feature worth reading twice
The README's multi-tenant example builds one SqlSugarClient from a list of ConnectionConfig objects, each with its own ConfigId, DbType and ConnectionString. Two entries appear: ConfigId "0" for SqlServer and ConfigId "1" for MySql, both with IsAutoCloseConnection set to true. From that single client you call GetConnection("1") for the MySQL handle and GetConnection("0") for the SQL Server handle. Then db.BeginTran() and an Insertable against the MySQL handle.
The point is that the transaction is opened on the client, not on either connection, so writes to two engines commit or roll back together within the scope of that client. This is the strongest argument for SqlSugar over a single-engine mapper, and it is also where you should slow down. Distributed commit across two engines is a hard problem. Treat this as a convenience wrapper whose failure semantics you must confirm against your own engines before you rely on it in production.
Where SqlSugar is the wrong choice
If your application talks to one database, the provider matrix buys you nothing and costs you indirection. Every query goes through expression translation, so the SQL in your source is not the SQL on the wire. The AOP hook mitigates that, but it is a debugging aid, not a substitute for reading the statement.
Second, engine-specific features are the weak spot by design. A single API that spans DuckDb, TDengine, QuestDb and DB2 cannot surface each engine's own capabilities uniformly. When you need something only one engine offers, you are back to raw SQL, and at that point you are maintaining two styles in one codebase.
Third, the documentation is split. The README points to GitHub wiki pages for NUGET, query, insert, update and delete, and to a separate site at donet5.com for cross-database query, Include insert, Include update, Include delete and JSON insert and update. The README itself is a feature tour with code samples, not a reference. Budget time for reading two documentation sources in two languages.
Finally, the release cadence visible in the repository is uneven: 5.1.4.167 on 2024-08-19, then 5.1.4.187 on 2025-03-29, then 5.1.4.197 on 2025-07-06. The last push to the default branch was on 2026-09-13, so the project is still being touched, but the tagged releases are not monthly. Pin a version and read the release note before moving.
SqlSugar against Dapper and FreeSql
Dapper is the opposite approach. It maps rows to objects from SQL you write yourself, with no expression translation and no provider abstraction beyond ADO.NET. That means no cross-database transaction wrapper and no Includes, but also no generated SQL to inspect. If your team is comfortable writing SQL and wants the database to be the source of truth, Dapper is the smaller commitment. SqlSugar is for teams that would rather write C# and let the ORM produce the statement.
FreeSql is the closer comparison. The repository description markets SqlSugar as a ".NET AOT ORM". The README confirms SqlSugar's supported .NET versions and its provider list, but not its AOT trimming behaviour, so that comparison has to be settled by building both against your own project rather than by reading either README.
Licence and upgrade cost
SqlSugar is MIT licensed, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is a permissive licence with no copyleft obligation. This is a description of the licence text, not legal advice; if your organisation has a policy on third-party dependencies, run it through that policy rather than through this article.
The upgrade cost is mostly the version pin. Releases are tagged and the README does not document a deprecation policy, so the practical approach is to pin the package to a specific version, read the release note for the next one, and upgrade deliberately. If you use three engines, your test matrix for an upgrade is three engines. The AOP logging hook is the cheapest way to see whether an upgrade changed the SQL your queries produce, since it prints the statement before execution.
Editorial conclusion
SqlSugar fits teams running the same C# codebase against several engines, or shipping to customers who each bring their own database, because the provider list and the cross-database transaction support are the reason to pick it over a single-engine mapper. It does not fit teams that want one engine, minimal abstraction, and SQL they can read directly in the source, since the query layer builds SQL for you. Before adopting, verify that your specific engine appears in the README's supported list, check the wiki page for your database's ConnectionConfig DbType value, and read the AOP logging hooks so you can see the SQL it emits.
Frequently asked questions
What is SQL software used for?
SqlSugar itself is a .NET ORM: it maps C# classes to tables and builds the SQL for you, so you write queries in C# instead of SQL strings.
What does SQL stand for?
The README describes SqlSugar as a .NET ORM framework that supports databases such as MySql, SqlServer, Sqlite, Oracle, postgresql and Mongodb.
Is SQL a programming language like Python?
It presents SqlSugar as a C# and VB.NET ORM, and its examples are C# lambdas that the library translates into SQL for the target database.
Is MySQL a programming language?
It lists MySql as one of the databases SqlSugar supports, alongside SqlServer, Sqlite, Oracle, postgresql and Mongodb, and shows it being configured through ConnectionConfig with DbType.MySql.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/dotnetnext-sqlsugar)Star history chart for your README
[](https://hysenlabs.com/projects/dotnetnext-sqlsugar)Was this useful?