DatabaseWrapper 6.1.0

dotnet add package DatabaseWrapper --version 6.1.0                
NuGet\Install-Package DatabaseWrapper -Version 6.1.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DatabaseWrapper" Version="6.1.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DatabaseWrapper --version 6.1.0                
#r "nuget: DatabaseWrapper, 6.1.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install DatabaseWrapper as a Cake Addin
#addin nuget:?package=DatabaseWrapper&version=6.1.0

// Install DatabaseWrapper as a Cake Tool
#tool nuget:?package=DatabaseWrapper&version=6.1.0                

DatabaseWrapper

Library Version Downloads
DatabaseWrapper (all supported database types) NuGet Version NuGet
DatabaseWrapper.Mysql NuGet Version NuGet
DatabaseWrapper.Postgresql NuGet Version NuGet
DatabaseWrapper.Sqlite NuGet Version NuGet
DatabaseWrapper.SqlServer NuGet Version NuGet
DatabaseWrapper.Core NuGet Version NuGet
ExpressionTree NuGet Version NuGet

DatabaseWrapper is the EASIEST and FASTEST way to get a data-driven application up and running using SQL Server, MySQL, PostgreSQL, or Sqlite.

For a sample app exercising this library, refer to the numerous Test projects contained within the solution.

Core features:

  • Dynamic query building
  • Hierarchical Boolean logic using Expression objects
  • Support for SQL server native vs Windows authentication
  • Support for SELECT, INSERT, UPDATE, DELETE, TRUNCATE, CREATE, DROP or raw queries
  • Programmatic table creation and removal (drop)
  • Built-in sanitization
  • Support for .NET Standard, .NET Core, and .NET Framework
  • Support for SQL Server, Sqlite, PostgreSQL, MySQL, MariaDB, both on-premises and in the cloud
  • Both synchronous and asynchronous APIs

New in v6.0.x

  • Minor breaking changes (API name changes)
  • Asynchronous APIs
  • Updated dependencies
  • Bugfixes

Special Thanks

Special thanks to those who have helped contribute or otherwise improve the library!

@shawty @constantinje @thedarklort @l-404-l @igrgurina @Vaelek @treyhay31 @daoye @twobytescy @rinkusahu1

A Note on Sanitization

Use of parameterized queries vs building queries dynamically is a sensitive subject. Proponents of parameterized queries have data on their side - that parameterization does the right thing to prevent SQL injection and other issues. I do not disagree with them. However, it is worth noting that with proper care, you CAN build systems that allow you to dynamically build queries, and you SHOULD do so as long as you build in the appropriate safeguards.

If you find an injection attack that will defeat the sanitization layer built into this project, please let me know!

Simple Example

Refer to the test project for a more complete example with sample table setup scripts.

using DatabaseWrapper;
using DatabaseWrapper.Core;
using ExpressionTree;

DatabaseClient client = null;

// Sqlite
client = new DatabaseClient("[databasefilename]");

// SQL Server, MySQL, or PostgreSQL
client = new DatabaseClient(DbTypes.SqlServer,  "[hostname]", [port], "[user]", "[password]", "[databasename]");
client = new DatabaseClient(DbTypes.Mysql,      "[hostname]", [port], "[user]", "[password]", "[databasename]");
client = new DatabaseClient(DbTypes.Postgresql, "[hostname]", [port], "[user]", "[password]", "[databasename]");

// SQL Express
client = new DatabaseClient(DbTypes.SqlServer,  "[hostname]", [port], "[user]", "[password]", "[instance]", "[databasename]");

// some variables we'll be using
Dictionary<string, object> d;
Expr e;
List<string> fields;
DataTable result;

// add a record
d = new Dictionary<string, object>();
d.Add("firstName", "Joel");
d.Add("lastName", "Christner");
d.Add("notes", "Author");
result = client.Insert("person", d);
result = await client.InsertAsync("person", d);

// update a record
d = new Dictionary<string, object>();
d.Add("notes", "The author :)");
e = new Expr("firstName", OperatorEnum.Equals, "Joel"); 
client.Update("person", d, e);
await client.UpdateAsync("person", d, e);

// retrieve 10 records
fields = new List<string> { "firstName", "lastName" }; // leave null for *
e = new Expr("lastName", OperatorEnum.Equals, "Christner"); 
ResultOrder[] order = new ResultOrder[1];
order = new ResultOrder("firstName", OrderDirectionEnum.Ascending)
result = client.Select("person", 0, 10, fields, e, order);
result = await client.SelectAsync("person", 0, 10, fields, e, order);

// delete a record
e = new Expr("firstName", Operators.Equals, "Joel"); 
client.Delete("person", e);
await client.DeleteAsync("person", e);

// execute a raw query
result = client.Query("SELECT customer_id FROM customer WHERE customer_id > 10");
result = await client.QueryAsync("SELECT customer_id FROM customer WHERE customer_id > 10");

Sample Compound Expression

Expressions, i.e. the Expr class from ExpressionTree, can be nested in either the Left or Right properties. Conversion from Expr to a WHERE clause uses recursion, so you have a good degree of flexibility in building your expressions in terms of depth.

Expr e = new Expr {
	Left = new Expr("age", OperatorEnum.GreaterThan, 30),
	Operator = Operators.And,
	Right = new Expr("height", OperatorEnum.LessThan, 74)
};

Select with Pagination

Use IndexStart, MaxResults, and ResultOrder[] to retrieve paginated results. The query will retrieve maxResults records starting at row number indexStart using an ordering based on orderByClause. See the example in the DatabaseWrapperTest project.

IMPORTANT: When doing pagination with SQL Server, you MUST specify an ResultOrder[].

ResultOrder[] order = new ResultOrder[1];
order = new ResultOrder("firstName", OrderDirectionEnum.Ascending);
DataTable result = client.Select("person", 5, 10, null, e, order);

Need a Timestamp?

We added a simple static method for this which you can use when building expressions (or elsewhere). An object method exists as well.

string ts = client.Timestamp(DateTime.Now);
// 08/23/2016 05:34:32.4349034 PM

string tso = client.Timestamp(DateTime.Now);
// 2016-08-23 17:34:32.446913 

Other Notes

General

When using database-specific classes DatabaseWrapper.Mysql, DatabaseWrapper.Postgresql, DatabaseWrapper.SqlServer, or DatabaseWrapper.Sqlite, the constructor is simplified from what is shown above.

For Sqlite:

DatabaseClient client = new DatabaseClient("[databasefilename]");

For SQL Server, MySQL, or PostgreSQL:

DatabaseClient client = new DatabaseClient(DbTypes.SqlServer,  "[hostname]", [port], "[user]", "[password]", "[databasename]");
DatabaseClient client = new DatabaseClient(DbTypes.Mysql,      "[hostname]", [port], "[user]", "[password]", "[databasename]");
DatabaseClient client = new DatabaseClient(DbTypes.Postgresql, "[hostname]", [port], "[user]", "[password]", "[databasename]");

For SQL Server Express:

DatabaseClient client = new DatabaseClient(DbTypes.SqlServer, "[hostname]", [port], "[user]", "[password]", "[instance]", "[databasename]");

MySQL

  • MySQL does not like to return updated rows. I thought about making the UPDATE clause require that you supply the ID field and the ID value so that I could retrieve it after the fact, but that approach is just too limiting.

MariaDB

  • Use the MySQL constructor. MySQL constraints remain.

PostgreSQL

  • Cleansing of strings in PostgreSQL uses the dollar-quote style. Fieldnames are always encapsulated in double-quotes for PostgreSQL.

SQL Server

  • Pagination where IndexStart and MaxResults are supplied demands use of ResultOrder[].

Sqlite

  • Sqlite may not work out of the box with .NET Framework. In order to use Sqlite with .NET Framework, you'll need to manually copy the runtimes folder into your project output directory. This directory is automatically created when building for .NET Core. To get this folder, build the Test.Sqlite project and navigate to the bin/debug/netcoreapp* directory. Then copy the runtimes folder into the project output directory of your .NET Framework application.

Version history

Refer to CHANGELOG.md.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  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 is compatible.  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. 
.NET Framework net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on DatabaseWrapper:

Package Downloads
RestDb

RestDb is a platform that enables a RESTful API interface in front of Microsoft SQL Server, MySQL, PostgreSQL, and Sqlite databases.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
6.1.0 221 9/19/2024
6.0.7 441 3/27/2024
6.0.6 1,144 10/4/2023
6.0.5 1,712 8/29/2023
6.0.3 3,406 7/11/2023
6.0.2 1,003 7/11/2023
6.0.1 907 7/11/2023
6.0.0 935 7/11/2023
5.0.2 2,919 2/2/2023
5.0.0 3,117 10/25/2022
4.1.5 2,990 8/29/2022
4.1.3 1,466 6/21/2022
4.1.2 1,249 5/27/2022
4.0.0.1 2,020 12/31/2021
4.0.0 1,072 12/31/2021
3.3.2.3 1,071 12/22/2021
3.3.2.1 1,436 11/20/2021
3.3.2 2,039 11/19/2021
3.3.1.5 1,046 11/12/2021
3.3.1.2 5,448 6/7/2021
3.3.1.1 2,869 4/14/2021
3.3.1 1,154 4/14/2021
3.3.0 2,069 3/2/2021
3.2.2.18 2,362 2/9/2021
3.2.2.17 4,394 12/26/2020
3.2.2.16 2,626 11/28/2020
3.2.2.15 1,332 11/26/2020
3.2.2.13 1,380 11/25/2020
3.2.2.12 1,347 11/25/2020
3.2.2.11 1,586 11/24/2020
3.2.2.10 1,776 11/15/2020
3.2.2.9 1,635 11/10/2020
3.2.2.8 1,656 11/9/2020
3.2.2.7 1,615 10/19/2020
3.2.2.6 1,602 10/15/2020
3.2.2.5 1,675 10/5/2020
3.2.2.4 1,681 10/5/2020
3.2.2.3 1,768 9/18/2020
3.2.2.2 1,671 9/18/2020
3.2.2.1 1,746 9/18/2020
3.2.2 1,667 9/18/2020
3.2.0.7 1,817 9/16/2020
3.2.0.6 1,716 9/16/2020
3.2.0.5 1,604 9/10/2020
3.2.0.4 1,711 9/8/2020
3.2.0.3 1,988 9/8/2020
3.2.0.2 4,622 8/17/2020
3.2.0.1 4,648 7/28/2020
3.2.0 2,213 7/10/2020
3.1.0.3 2,259 6/20/2020
3.1.0.2 1,617 6/20/2020
3.1.0.1 2,166 6/11/2020
3.1.0 1,579 6/11/2020
3.0.1.2 1,852 6/10/2020
3.0.1.1 2,441 6/4/2020
3.0.1 1,858 6/3/2020
3.0.0.3 3,610 5/21/2020
3.0.0.2 2,203 5/20/2020
3.0.0 1,655 5/20/2020
2.0.5 5,392 5/12/2020
2.0.4 18,775 3/23/2020
2.0.3 1,636 3/23/2020
2.0.2 11,522 3/9/2020
2.0.1 1,842 3/9/2020
2.0.0 2,115 3/9/2020
1.5.1 38,847 12/18/2019
1.5.0 1,367 12/15/2019
1.4.7 17,631 10/1/2019
1.4.5 1,987 9/21/2019
1.4.4 1,652 8/22/2019
1.4.3 1,546 8/21/2019
1.4.2 1,567 8/21/2019
1.4.1 1,558 8/20/2019
1.4.0 1,505 8/19/2019
1.3.2 1,632 6/13/2019
1.3.1 2,084 4/25/2019
1.2.7 2,269 3/10/2019
1.2.6 2,129 3/20/2018
1.2.5 2,068 1/12/2018
1.2.4 2,000 12/28/2017
1.2.3 1,902 11/1/2017
1.2.2 1,928 9/25/2017
1.2.1 2,072 5/17/2017
1.1.9 1,918 5/3/2017
1.1.8 1,962 5/3/2017
1.1.7 2,010 5/3/2017
1.1.6 1,851 5/2/2017
1.1.5 1,987 3/29/2017
1.1.4 1,992 1/25/2017

Oracle support (thank you @Skimmenthal13!), bugfixes, dependency updates.