VQuery 1.0.6
dotnet add package VQuery --version 1.0.6
NuGet\Install-Package VQuery -Version 1.0.6
<PackageReference Include="VQuery" Version="1.0.6" />
<PackageVersion Include="VQuery" Version="1.0.6" />
<PackageReference Include="VQuery" />
paket add VQuery --version 1.0.6
#r "nuget: VQuery, 1.0.6"
#:package VQuery@1.0.6
#addin nuget:?package=VQuery&version=1.0.6
#tool nuget:?package=VQuery&version=1.0.6
VQuery
A lightweight, high-performance database library for .NET โ one simple API for MySQL, PostgreSQL, and SQL Server.
Why VQuery?
Most .NET projects end up choosing between hand-written ADO.NET (verbose, repetitive) or a full ORM like EF Core (heavy, opinionated, slow to set up for simple apps). VQuery sits in between:
- ๐ One API, three databases โ switch between MySQL, PostgreSQL, and SQL Server without rewriting your data layer
- โก Fast โ reflection caching means object mapping doesn't slow you down as your app grows
- ๐ชถ Lightweight โ no heavy configuration, no migrations engine, no fighting the framework
- ๐งต Async-first โ every core operation has an async counterpart
- ๐ Safe by default โ parameterized queries throughout
If you want Dapper-like simplicity with built-in multi-database support out of the box, VQuery is built for that.
Status: MySQL support is the most tested and battle-tested part of VQuery. PostgreSQL and SQL Server support exist and follow the same API, but have seen less real-world use so far โ feedback and bug reports for those are especially welcome.
Installation
dotnet add package VQuery
Or via the Package Manager Console:
Install-Package VQuery
Quick Start
1. Add a connection string to appsettings.json:
{
"ConnectionStrings": {
"MYSQLConnection": {
"server": "127.0.0.1",
"port": "3306",
"database": "sampledb",
"username": "root",
"password": "123456"
}
}
}
2. Query in three lines:
using VQuery;
using var db = new MySQLConnection();
db.ConnectionOpen("MYSQLConnection");
var users = db.Query<User>("SELECT * FROM users");
Swap MySQLConnection for PostgreSQLConnection or SQLServerConnection and everything else stays the same.
Core Features
| Feature | Description |
|---|---|
Query<T>() / QueryAsync<T>() |
Map query results directly to your model classes |
QueryFirst<T>() / QuerySingle<T>() |
Grab a single record with less boilerplate |
QueryFirstOrDefault<T>() / QuerySingleOrDefault<T>() |
Same as above, but return default instead of throwing when no rows are found |
QueryMultiple() |
Run multiple SELECT statements and get back a DataSet |
SelectDataTable() / SelectDataRow() / SelectDataValue() |
Lower-level access when you don't need object mapping |
ExecuteScalar<T>() |
Return a single value (counts, sums, etc.) |
ExecuteNonQuery() |
Run INSERT/UPDATE/DELETE and get back the affected row count |
Execute() / ExecuteRun() |
Run a statement and get back a bool instead of a row count |
Insert() / Update() / Delete() |
Simple CRUD helpers |
Exists() / ExistsAsync() |
Check whether a query returns any matching rows |
Begin() / Commit() / RollBack() |
Full transaction support |
| Connection pooling | Configurable min/max pool size out of the box |
VariableConverter |
Type-conversion utilities available directly on the connection object |
Usage Examples
CRUD
// Insert
db.Insert("users", new Dictionary<string, string>
{
{ "name", "John" },
{ "email", "john@test.com" }
});
// Update
db.Update("users", new Dictionary<string, string>
{
{ "name", "David" }
}, "id=1");
// Delete (parameterized)
db.Delete("DELETE FROM users WHERE id=@id", new() { ["@id"] = 1 });
Note:
Insert()andUpdate()also have overloads that takeDictionary<string, object>instead ofDictionary<string, string>. Prefer theobjectoverloads when your values include numbers, dates, or booleans โ thestringoverloads pass every value through asVARCHAR.
Check existence
bool hasAdmins = db.Exists("SELECT 1 FROM users WHERE role=@role", new() { ["@role"] = "admin" });
bool hasAdminsAsync = await db.ExistsAsync("SELECT 1 FROM users WHERE role=@role", new() { ["@role"] = "admin" });
Transactions
db.Begin();
try
{
db.Insert("users", new Dictionary<string, string> { { "name", "John" } });
db.Update("users", new Dictionary<string, string> { { "name", "David" } }, "id=1");
db.Commit();
}
catch
{
db.RollBack();
}
Async
var users = await db.QueryAsync<User>("SELECT * FROM users");
var user = await db.QueryFirstAsync<User>(
"SELECT * FROM users WHERE id=@id",
new() { ["@id"] = 1 });
Safe single-record lookups
// Returns default(T) instead of throwing when no row is found
var user = db.QueryFirstOrDefault<User>(
"SELECT * FROM users WHERE id=@id", new() { ["@id"] = 1 });
var userAsync = await db.QueryFirstOrDefaultAsync<User>(
"SELECT * FROM users WHERE id=@id", new() { ["@id"] = 1 });
QuerySingle<T>() / QuerySingleOrDefault<T>() (and their async versions) work the same way, but throw if more than one row is returned.
VariableConverter utilities
Available directly on the connection object for quick type conversions:
db.ToInt("100"); // -> 100
db.ToDouble("123.45"); // -> 123.45
db.ToIntString(100); // -> "100"
db.ToDoubleString(123.45); // -> "123.45"
db.ToString(DateTime.Now); // -> formatted string
db.ToStringDate(DateTime.Now); // -> "dd-MM-yyyy" by default
db.ToStringDateTime(DateTime.Now); // -> "dd-MM-yyyy HH:mm:ss" by default
db.ToDate("01-01-2026"); // -> DateTime
db.ToDateTime("01-01-2026 10:00:00");// -> DateTime
db.NumberToText(1000); // -> number spelled out in words
db.NumberToTextKH(1000); // -> number spelled out in Khmer
db.NumberToKhNumber(1000); // -> number in Khmer numerals
db.IsEmpty(row); // -> true if a DataRow has no data
Multiple result sets
string sql = @"
SELECT * FROM users;
SELECT * FROM roles;
";
DataSet ds = db.QueryMultiple(sql);
DataTable users = ds.Tables[0];
DataTable roles = ds.Tables[1];
Configuration Reference
Each connection block in appsettings.json supports:
| Key | Description | Default |
|---|---|---|
server |
Host address | โ |
port |
Port number | DB-specific |
database |
Database name | โ |
username / password |
Credentials | โ |
pooling |
Enable connection pooling | true |
minimumPoolSize / maximumPoolSize |
Pool size range | 5 / 100 |
connectionTimeout |
Seconds before connection timeout | 30 |
commandTimeout |
Seconds before command timeout | 60 |
trustServerCertificate |
SQL Server only | false |
Supported Frameworks
- .NET 8.0 (also compatible with .NET 9.0 / 10.0)
Dependencies
Microsoft.Data.SqlClient(>= 7.0.1)Microsoft.Extensions.Configuration.Json(>= 8.0.0)MySql.Data(>= 8.4.0)Npgsql(>= 8.0.3)
Contributing
Issues and pull requests are welcome! If you find a bug or have a feature request, please open an issue.
License
MIT โ free to use in personal and commercial projects.
Links
- ๐ฆ NuGet Package
- ๐ป Source Code
| Product | Versions 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 was computed. 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 was computed. 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. |
-
net8.0
- Microsoft.Data.SqlClient (>= 7.0.1)
- Microsoft.Extensions.Configuration.Json (>= 8.0.0)
- MySql.Data (>= 8.4.0)
- Npgsql (>= 8.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.