{"id":28052650,"url":"https://github.com/vpetkovic/simplex","last_synced_at":"2026-02-16T20:05:51.023Z","repository":{"id":42486236,"uuid":"437616435","full_name":"vpetkovic/simplex","owner":"vpetkovic","description":".NET library that provides simplified data access layer for interaction with ADO.NET data sources","archived":false,"fork":false,"pushed_at":"2022-11-29T15:46:10.000Z","size":62,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-09T02:32:02.018Z","etag":null,"topics":["database","mssql","mysql","postgresql","sinks"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vpetkovic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-12-12T17:51:37.000Z","updated_at":"2023-01-11T12:45:25.000Z","dependencies_parsed_at":"2023-01-21T11:30:47.379Z","dependency_job_id":null,"html_url":"https://github.com/vpetkovic/simplex","commit_stats":null,"previous_names":["vpetkovic/cl.sinks"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/vpetkovic/simplex","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetkovic%2Fsimplex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetkovic%2Fsimplex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetkovic%2Fsimplex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetkovic%2Fsimplex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vpetkovic","download_url":"https://codeload.github.com/vpetkovic/simplex/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetkovic%2Fsimplex/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263480853,"owners_count":23473162,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","mssql","mysql","postgresql","sinks"],"created_at":"2025-05-12T02:16:07.008Z","updated_at":"2026-02-16T20:05:50.968Z","avatar_url":"https://github.com/vpetkovic.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n[![Build status](https://dev.azure.com/vpetkovic/HelperTools/_apis/build/status/HelperTools/HelperTools)](https://dev.azure.com/vpetkovic/HelperTools/_build/latest?definitionId=3)\n| CL.Sinks Package | NuGet | Version | Stats |\n| --------------- | --------------- | --------------- | --------------- |\n| SqlServer | [`Install-Package CL.Sinks.SqlServer`](https://www.nuget.org/packages/CL.Sinks.SqlServer/) | ![Nuget](https://img.shields.io/nuget/v/CL.Sinks.SqlServer) | ![Nuget](https://img.shields.io/nuget/dt/CL.Sinks.SqlServer?label=%20Downloads)\n| MySql | [`Install-Package CL.Sinks.MySql`](https://www.nuget.org/packages/CL.Sinks.MySql/) | ![Nuget](https://img.shields.io/nuget/v/CL.Sinks.MySql) | ![Nuget](https://img.shields.io/nuget/dt/CL.Sinks.MySql?label=%20Downloads) |\n| MySql Backup | [`Install-Package CL.Sinks.MySql.Backup`](https://www.nuget.org/packages/CL.Sinks.MySql.Backup/) | ![Nuget](https://img.shields.io/nuget/v/CL.Sinks.MySql.Backup) | ![Nuget](https://img.shields.io/nuget/dt/CL.Sinks.MySql.Backup?label=%20Downloads) |\n| PostgreSql | [`Install-Package CL.Sinks.PostgreSql`](https://www.nuget.org/packages/CL.Sinks.PostgreSql/) | ![Nuget](https://img.shields.io/nuget/v/CL.Sinks.PostgreSql) | ![Nuget](https://img.shields.io/nuget/dt/CL.Sinks.PostgreSql?label=%20Downloads)\n\n## Description\n`CL.Sinks` is simple .NET library wrapped around Dapper ORM with a goal to simplify interactions with relational databases. \n\n## Background\nThe main motivation comes from unavoidable interaction with data sources, mainly ADO.NET providers, at work and for personal projects and dealing with repetative helper methods in each to handle connections and executing queries and stored procedures. \nSide note: I gave it a shot, but never seemed to adapt and get to like \"code-first\" approach with Entity Framework mainly because it is difficult to modify any table/field without having to constantly dealing with migrations back and forth. \n\nI needed very simple, fast and easy to setup data access layer for SqlServer, MySql and PostgreSql.\n\n## Basic Usage\n\nThis basic example demonstrates how quickly you can connect and query your database whether it is SqlServer, MySql or PostgreSql. \nThis is most appropriate approach for very simple projects or quick testing where as for more complex projects and scenarios that interact with multiple databases and database providers check out [more advanced usage](#advanced-and-production-ready-usage) examples\n``` c#\n// Connection strings will vary among providers. \nvar connection = new Connection() { ConnectionString = \"connection string\" };\n\n// Sql Server\nvar users = new SqlDataAccess(connection).LoadFromStoredProcedureAsync\u003cUsers\u003e(\"sp_GetUsers\");\n\n// PostgreSql Server\nvar users = new PostgreSqlDataAccess(connection).LoadFromStoredProcedureAsync\u003cUsers\u003e(\"sp_GetUsers\");\n\n// MySql\nvar users = new MySqlDataAccess(connection).LoadFromStoredProcedureAsync\u003cUsers\u003e(\"sp_GetUsers\");\n```\n\u003chr\u003e\n\n## Advanced Usage\n\nThere are several ways you can define your connections to different databases and database types. Most of the time you will end up using `appsettings.json` for it as connection strings will most likely come from some secrets manager services. Any connection string with connection name of \"Default\" will be mapped and considered your default connection.\n\n`appsettings.json`\n``` json\n{\n  \"ConnectionStrings\": {\n    \"Default\": \"sql server connection string\",\n    \"MySql\": \"connection string\",\n    \"PostgreSql\": \"connection string\"\n  }\n}\n```\n\nIf however, that is not the case and you want to hard code connecton strings you can define the list of connections by using `Connection` object\n``` c#\npublic struct ConnectionStrings\n{\n    public static List\u003cConnection\u003e Connections = new()\n    {\n        new Connection\n        {\n            Name= \"Default\",\n            ConnectionString = \"sql server connection string\",\n            IsDefault = true,\n        },\n        new Connection\n        {\n            Name= \"MySql\",\n            ConnectionString = \"connection string\",\n            ConnectionTimeout = 120,\n        },\n        new Connection\n        {\n            Name= \"PostgreSql\",\n            ConnectionString = \"connection string\"\n        }\n    };\n}\n```\n\nThe chances are that you will be using `Dependency Injection` to register data access providers. Let's showcase scenario with single provider and multiple providers and how you'd register and inject them in your app\n\nRegister services in `program.cs` (.NET 6) or `startup.cs` (.NETCore 3.1 - .NET 5) would be the same for both scenarios - you'd just register each provider as singleton\n``` c#\n\n// If you have defined connections in appsettings.json \nIConfiguration config = new ConfigurationBuilder()\n    .AddJsonFile(\"appsettings.json\", false)\n    .Build();\n\nvar serviceProvider = new ServiceCollection()\n    .AddSingleton\u003cISqlDataAccess, SqlDataAccess\u003e(_ =\u003e new SqlDataAccess(new ConnectionSettings(config)))\n    .AddSingleton\u003cISqlDataAccess, PostgreSqlDataAccess\u003e(_ =\u003e new PostgreSqlDataAccess(new ConnectionSettings(config)))\n    .AddSingleton\u003cISqlDataAccess, MySqlDataAccess\u003e(_ =\u003e new MySqlDataAccess(new ConnectionSettings(config)\n    {\n        // You can specify default timeout for all connection strings. if not set it will default to 30 seconds\n        GlobalConnectionTimeout = 90\n    }))\n    .BuildServiceProvider();\n...\n    \n// If you have hard coded the definitions of connection strings in code behind\nvar serviceProvider = new ServiceCollection()\n    .AddSingleton\u003cISqlDataAccess, SqlDataAccess\u003e(_ =\u003e new SqlDataAccess(new ConnectionSettings(ConnectionStrings.Connections)))\n    .AddSingleton\u003cISqlDataAccess, PostgreSqlDataAccess\u003e(_ =\u003e new PostgreSqlDataAccess(new ConnectionSettings(ConnectionStrings.Connections)))\n    .AddSingleton\u003cISqlDataAccess, MySqlDataAccess\u003e(_ =\u003e new MySqlDataAccess(new ConnectionSettings(ConnectionStrings.Connections)))\n    .BuildServiceProvider();\n...   \n```\n\n#### Single Provider Usage\n``` c#\n[ApiController]\n[Route(\"[controller]\")]\npublic class UsersController : ControllerBase\n{\n    private readonly ISqlDataAccess _sqlDataAccess;\n    \n    public UsersController(ISqlDataAccess dataProvider)\n    {\n        _sqlDataAccess = dataProvider;\n    }\n\n    [HttpGet(\"/sql/users\")]\n    public async Task\u003cList\u003cUser\u003e\u003e SqlUsers() =\u003e await _sqlDataAccess.LoadFromStoredProcedureAsync\u003cUser\u003e(\"sp_GetUsers\");\n    \n    [HttpGet(\"/sql/users/{id:int}\")]\n    public async Task\u003cUser\u003e SqlSingleUser() =\u003e await _sqlDataAccess.LoadFirstFromStoredProcedureAsync\u003cUser, dynamic\u003e(\"sp_GetUsers\", new {id});\n}\n```\n\n#### Multiple Providers Usage\n``` c#\n[ApiController]\n[Route(\"[controller]\")]\npublic class UsersController : ControllerBase\n{\n    private readonly ISqlDataAccess _sqlDataAccess;\n    private readonly ISqlDataAccess _mySqlDataAccess;\n    private readonly ISqlDataAccess _postgreSqlDataAccess;\n    \n    public UsersController(IEnumerable\u003cISqlDataAccess\u003e dataProviders)\n    {\n        _mySqlDataAccess = dataProviders.SingleOrDefault(s =\u003e s.GetType() == typeof(MySqlDataAccess));\n        _postgreSqlDataAccess = dataProviders.SingleOrDefault(s =\u003e s.GetType() == typeof(PostgreSqlDataAccess));\n        _sqlDataAccess = dataProviders.ElementAt(1);\n    }\n\n    [HttpGet(\"/sql/users\")]\n    public async Task\u003cList\u003cUser\u003e\u003e SqlUsers() =\u003e await _sqlDataAccess.LoadFromStoredProcedureAsync\u003cUser\u003e(\"sp_GetUsers\");\n    \n    [HttpGet(\"/sql/users/{id:int}\")]\n    public async Task\u003cUser\u003e SqlSingleUser() =\u003e await _sqlDataAccess.LoadFirstFromStoredProcedureAsync\u003cUser, dynamic\u003e(\"sp_GetUsers\", new {id});\n    \n    [HttpGet(\"/mysql/users\")]\n    public async Task\u003cList\u003cUser\u003e\u003e MySqlUsers() =\u003e await _mySqlDataAccess.LoadFromStoredProcedureAsync\u003cUser\u003e(\"sp_GetUsers\", \"MySql\");\n    \n    [HttpGet(\"/postgresql/users\")]\n    public async Task\u003cList\u003cUser\u003e\u003e PostgreSql() =\u003e await _postgreSqlDataAccess.LoadFromStoredProcedureAsync\u003cUser\u003e(\"sp_GetUsers\", \"PostgreSql\");\n}\n```\n\n### All Methods\n\n| Methods | Where | Returns | Notes |\n| --------------- | --------------- | --------------- | --------------- |\n| LoadFromSqlAsync\u003cT, T1\u003e | T required, T1 optional | List\\\u003cT\\\u003e |\n| LoadFirstFromSqlAsync\u003cT, T1\u003e | T required, T1 optional | T | If query returns collection first item will be returned\n| LoadFromStoredProcedureAsync\u003cT, T1\u003e | T required, T1 optional | List\\\u003cT\\\u003e |\n| LoadFirstStoredProcedureAsync\u003cT, T1\u003e | T required, T1 optional | T | If sp returns collection first item will be returned\n| SaveFromSqlAsync\\\u003cT\\\u003e | T optional | void |\n| SaveFromStoredProcedureAsync\\\u003cT\\\u003e | T optional | void |\n| SaveFromSql\\\u003cT\\\u003e | T optional | void |\n| SaveFromStoredProcedure\\\u003cT\\\u003e | T optional | void |\n\n\n\u003cbr\u003e\n\n## Extensions\n\n### Fluent Database Backup Extension\n\nRight now it is only supporting MySql backup but soon I will extend support for other database sinks and storage options ([choose priority](https://github.com/vpetkovic/CL.Sinks/discussions/8)) as well add restore functionality. \n*I am debating whether or not to combine this functionality into one extension or split them into multiple, one extension per sink. Feel free to drop your thoughts [here](https://github.com/vpetkovic/CL.Sinks/discussions/6)*\n\nAnyways, in meantime if you use MySql database here's the sample usage\n\n[`Install-Package CL.Sinks.MySql.Backup`](https://www.nuget.org/packages/CL.Sinks.MySql.Backup/)\n\n``` c#\n\nvar backupStatus = FluentMySqlBackup\n    .For(ConnectionStrings.Connections.FirstOrDefault(c =\u003e c.Name == \"MySql\"))\n    .Export(new string[] { \"all\" }) // individial db names or \"all\" for all databases on server\n    .ToLocalStorage(@\"C:\\users\\vpetkovic\\desktop\")\n        .Save() // multiThreaded = false\n    .ToAzure(\"AzureBlobConnectionString\")\n        .OnBlob(\"backup-db-container\")\n        .Upload(true) // true = multiThreaded\n    .Done();\n```\n\n`backupStatus` will return an object\n\n``` json\n{\n    Exceptions: [],\n    TotalBackupTimeMilliseconds: decimal,\n    isSuccess: bool,\n    IsRunning: bool,\n}\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvpetkovic%2Fsimplex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvpetkovic%2Fsimplex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvpetkovic%2Fsimplex/lists"}