{"id":37036263,"url":"https://github.com/perfectsquircle/toadstool","last_synced_at":"2026-01-14T04:18:20.600Z","repository":{"id":87365944,"uuid":"176193899","full_name":"perfectsquircle/toadstool","owner":"perfectsquircle","description":"The Dapper alternative that nobody asked for.","archived":false,"fork":false,"pushed_at":"2024-05-10T21:42:29.000Z","size":200,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-17T16:55:19.357Z","etag":null,"topics":["csharp","dapper","fluent","microorm","netcore","netframework","orm"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/perfectsquircle.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-18T02:56:28.000Z","updated_at":"2024-05-10T21:42:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"a645e30a-3f9e-4e65-aeb3-518aa4881132","html_url":"https://github.com/perfectsquircle/toadstool","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/perfectsquircle/toadstool","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/perfectsquircle%2Ftoadstool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/perfectsquircle%2Ftoadstool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/perfectsquircle%2Ftoadstool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/perfectsquircle%2Ftoadstool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/perfectsquircle","download_url":"https://codeload.github.com/perfectsquircle/toadstool/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/perfectsquircle%2Ftoadstool/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28409325,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["csharp","dapper","fluent","microorm","netcore","netframework","orm"],"created_at":"2026-01-14T04:18:20.010Z","updated_at":"2026-01-14T04:18:20.589Z","avatar_url":"https://github.com/perfectsquircle.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🍄 Toadstool\n\n\u003e The Dapper alternative that nobody asked for.\n\n[![NuGet version](https://img.shields.io/nuget/vpre/Toadstool.svg)](https://www.nuget.org/packages/Toadstool)\n\n## Features\n\n* Wraps ADO.NET with an async-first and fluent API.\n* Maps DataReader results to a strongly typed list of objects.\n* CRUD operations don't require boilerplate of creating a new connection, opening, and disposing it.\n* Transaction state can be carried between different repositories.\n\n```csharp\nvar stockItems = await context\n    .Select(\"stock_item_id\", \"stock_item_name\")\n    .From(\"warehouse.stock_items\")\n    .Where(\"supplier_id\").EqualTo(2)\n    .OrderBy(\"stock_item_name\")\n    .ToListAsync\u003cStockItem\u003e();\n```\n\n## Installation\n\n```bash\ndotnet add package Toadstool\n```\n\n--OR--\n\n```bat\nPM\u003e Install-Package Toadstool\n```\n\n## Usage\n\n### DbContext\n\nThe entrypoint into the Toadstool API is the `DbContext` class. Typically, only one of these should be created per database in your application lifetime (or HTTP Request lifetime.)\n\n```csharp\nvar context = new DbContext();\n```\n\nThe context must be able to create new instances of `IDbConnection`, so we pass it a `CreateConnection` delegate, which is just a function that returns a new connection with the driver of our choosing.\n\n```csharp\n// Use with SQL Server\nvar context = new DbContext(() =\u003e new SqlConnection(\"Server=...\")); \n// Use with PostgreSQL\nvar context = new DbContext(() =\u003e new NpgsqlConnection(\"Host=...\")); \n```\n\n### Statement Builder\n\n```csharp\nclass Customer {\n    public string FirstName { get; set; }\n    public string LastName { get; set;}\n    public int Age { get; set;}\n}\n\n// Do a SELECT then map the results to a list.\nIList\u003cCustomer\u003e customers = await context\n    .Select(\"first_name\", \"last_name\", \"age\")\n    .From(\"customer\")\n    .Where(\"last_name\").EqualTo(\"Cuervo\")\n    .ToListAsync\u003cCustomer\u003e();\n\n// Do a SELECT then grab the first result.\nCustomer customer = await context\n    .Select(\"first_name\", \"last_name\", \"age\")\n    .From(\"customer\")\n    .Where(\"customer_id\").EqualTo(777)\n    .FirstOrDefaultAsync\u003cCustomer\u003e();\n\n// Execute an INSERT\nint rowsAffected = await context\n    .InsertInto(\"customer\")\n    .Columns(\"first_name\", \"last_name\", \"age\")\n    .Values(\"Peter\", \"Rabbit\", 100)\n    .Values(\"Santa\", \"Clause\", 1000)\n    .Execute();\n\n// Execute an UPDATE\nint rowsAffected = await context\n    .Update(\"customer\")\n    .Set(\"first_name\").EqualTo(\"Jerry\")\n    .Set(\"last_name\").EqualTo(\"Seinfeld\")\n    .Where(\"last_name\").EqualTo(\"Cuervo\")\n    .Execute();\n\n// Execute a DELETE\nint rowsAffected = await context\n    .DeleteFrom(\"customer\")\n    .Where(\"last_name\").EqualTo(\"Cuervo\")\n    .Execute();\n```\n\n### Custom Statements\n\nThe statement builder shown above is optional. Statements can also be passed in as plain strings.\n\n```csharp\nclass Customer {\n    public string FirstName { get; set; }\n    public string LastName { get; set;}\n}\n\n// Do a SELECT then map the results to a list.\nIList\u003cCustomer\u003e customers = await context\n    .CreateCommand(@\"SELECT first_name, last_name FROM customer WHERE last_name = @lastName\")\n    .WithParameter(\"lastName\", \"Cuervo\")\n    .ToListAsync\u003cCustomer\u003e();\n\n// Execute an INSERT\nint rowsAffected = await context\n    .CreateCommand(@\"INSERT INTO customer(fist_name, last_name) VALUES (@firstName, @lastName)\")\n    .WithParameters(new {\n        firstName = \"Jose\",\n        lastName = \"Cuervo\"\n    })\n    .Execute();\n\n// Execute an UPDATE\nint rowsAffected = await context\n    .CreateCommand(@\"UPDATE customer SET first_name = @firstName where last_name = @lastName\")\n    .WithParameter(\"firstName\", \"Jerry\")\n    .WithParameter(\"lastName\", \"Cuervo\")\n    .Execute();\n\n// Execute a DELETE\nint rowsAffected = await context\n    .CreateCommand(@\"DELETE FROM customer where last_name = @lastName\")\n    .WithParameter(\"lastName\", \"Cuervo\")\n    .Execute();\n\n// Execute a scalar\nstring firstName = await context\n    .CreateCommand(@\"SELECT first_name FROM customer WHERE id = 42\")\n    .ExecuteAsync\u003cstring\u003e();\n\n// Execute a stored procedure\nList\u003cCustomers\u003e customers = await context\n    .CreateCommand(@\"spGetCustomers\")\n    .WithParameter(\"lastName\", \"Cuervo\")\n    .WithCommandType(CommandType.StoredProcedure)\n    .ToListAsync\u003cCustomer\u003e();\n```\n\n### Transactions\n\nTo start a new database transaction, call `BeginTransaction` on `DbContext`. Once a transaction is begun on an instance of `DbContext`, all statements executed against that context automatically join the transaction on the same connection. Once the transaction is disposed, the context returns to normal connection pooling behavior.\n\n```csharp\nusing (var transaction = context.BeginTransaction())\n{\n    // Automatically joins the transaction\n    var results1 = await context.Select(\"1\").ExecuteAsync\u003cint\u003e(); \n    // Automatically joins the transaction\n    var results2 = await context.Select(\"2\").ExecuteAsync\u003cint\u003e();\n\n    transaction.Commit();\n} \n\n// Transaction is disposed, context returns to normal connection pool.\nvar results3 = await context.Select(\"3\").ExecuteAsync\u003cint\u003e(); // Normal \"anonymous\" call (not in transaction)\n```\n\nThis is useful because different repositories sharing the same `DbContext` instance can also share transactions. Say you have a service class with several repositories. Because you're using dependency injection, each of those repositories shares the same `DbContext` instance....\n\n```csharp\npublic async Task PlaceCustomerOrder(CustomerDetails customerDetails, OrderDetails orderDetails)\n{\n    using (var transaction = await _context.BeginTransactionAsync())\n    {\n        // Automatically joins the transaction\n        var userId = await _userRepository.CreateCustomer(customerDetails);\n        // Automatically joins the transaction\n        var orderId = await _orderRepository.CreateOrder(orderDetails); \n        // Automatically joins the transaction\n        var fulfillmentTicket = await _fulfillmentRepository.CreateFulfillmentTicket(userId, orderId);\n\n        transaction.Commit();\n    }\n}\n```\n\nTraditionally (with ADO or Dapper) you would have to pass around instances of your `IDbConnection` and `IDbTransaction` as method parameters, which is messy, rewrite a boilerplate connection provider class every time, or resort to using TransactionScope, which some developers believe is Dark Magic.\n\n### Dependency Injection\n\nIf you're using a IoC container, like the one in AspNetCore, it's best to have `DbContext` be registered as \"Scoped\".\n\n```csharp\nservices.AddScoped\u003cIDbContext\u003e(\n    (sp) =\u003e new DbContext(() =\u003e new SqlConnection(\"Server=...\"))\n);\n```\n\nThis way, everything in the same request scope can share transactions.\n\n## Building\n\nPrerequisites:\n* .NET Core SDK 2.1 \n* Mono or .NET Framework\n* Gnu Make\n\nTo build the NuGet package.\n\n```bash\nmake pack\n```\n\nThis project targets both .NET Standard 2.0 and .NET Framework 4.5.1. Because of this, you must have .NET Framework or Mono installed (in addition to .NET Core).\n\nOn macOS and Linux build environments, to build from .NET Core you must set the `FrameworkPathOverride` environment variable.\n\n```bash\nexport FrameworkPathOverride=$(dirname $(which mono))/../lib/mono/4.5/\n```\n\nSee https://github.com/dotnet/sdk/issues/335\n\n## Testing\n\nPrerequisites:\n* .NET Core SDK 2.1\n* Gnu Make\n* Docker\n* Bash\n\nRunning the integration tests requires having a recent version of Docker installed. Two database servers (PostgreSQL and SQL Server) will be brought up with \n\n```bash\nmake databases\n```\n\nAfter the servers are up and the databases are restored, the tests can be run.\n\n```bash\nmake test\n```\n\nTo bring down the servers and clean up the backup files,\n\n```bash\nmake clean-databases\n```\n\n\nBuilt with \u0026hearts; by Calvin.\n\n\u0026copy; Calvin Furano","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fperfectsquircle%2Ftoadstool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fperfectsquircle%2Ftoadstool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fperfectsquircle%2Ftoadstool/lists"}