{"id":19993073,"url":"https://github.com/tallesl/net-Query","last_synced_at":"2025-05-04T12:30:45.643Z","repository":{"id":25502540,"uuid":"28933911","full_name":"tallesl/net-Query","owner":"tallesl","description":"A simplistic ADO.NET wrapper.","archived":false,"fork":false,"pushed_at":"2018-09-13T13:37:54.000Z","size":2507,"stargazers_count":9,"open_issues_count":2,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-30T19:41:26.387Z","etag":null,"topics":["ado-net","csharp","dot-net","micro-orm","query-builder","sql","transaction"],"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/tallesl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-01-07T21:00:49.000Z","updated_at":"2024-05-10T20:47:33.000Z","dependencies_parsed_at":"2022-08-01T05:18:07.799Z","dependency_job_id":null,"html_url":"https://github.com/tallesl/net-Query","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tallesl%2Fnet-Query","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tallesl%2Fnet-Query/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tallesl%2Fnet-Query/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tallesl%2Fnet-Query/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tallesl","download_url":"https://codeload.github.com/tallesl/net-Query/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252334086,"owners_count":21731333,"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":["ado-net","csharp","dot-net","micro-orm","query-builder","sql","transaction"],"created_at":"2024-11-13T04:52:27.083Z","updated_at":"2025-05-04T12:30:40.632Z","avatar_url":"https://github.com/tallesl.png","language":"C#","readme":"\u003cp align=\"center\"\u003e\r\n    \u003ca href=\"#query\"\u003e\r\n        \u003cimg alt=\"logo\" src=\"Images/logo-200x200.png\"\u003e\r\n    \u003c/a\u003e\r\n\u003c/p\u003e\r\n\r\n# Query\r\n\r\n[![][build-img]][build]\r\n[![][nuget-img]][nuget]\r\n\r\n[build]:     https://ci.appveyor.com/project/TallesL/net-Query\r\n[build-img]: https://ci.appveyor.com/api/projects/status/github/tallesl/net-Query?svg=true\r\n[nuget]:     https://www.nuget.org/packages/Query/\r\n[nuget-img]: https://badge.fury.io/nu/Query.svg\r\n\r\nA simplistic ADO.NET wrapper.\r\n\r\n* [Instantiating](#instantiating)\r\n* [Modifying data](#modifying-data)\r\n* [Retrieving data](#retrieving-data)\r\n* [Behind the covers](#behind-the-covers)\r\n* [Thread safety](#thread-safety)\r\n* [Connections and Transactions](#connections-and-transactions)\r\n* [IN clauses](#in-clauses)\r\n* [SELECT clauses](#select-clauses)\r\n\r\n## Instantiating\r\n\r\n```cs\r\nvar query = new Query(\"Data Source=server; Initial Catalog=database; User ID=user; Password=password;\", \"System.Data.SqlClient\");\r\n```\r\n\r\nThere's some optional arguments besides the query string and the provider name:\r\n\r\n* `enumAsString`: Treat enum values as strings rather than as integers;\r\n* `manualClosing`: Connection/transaction closing should be done 'manually' instead of automatically on each call (see\r\n[\"Connections and Transactions\"](#connections-and-transactions));\r\n* `safe`: Throws if a selected property is not found in the given type;\r\n* `commandTimeout`: Optional [DBCommand.CommandTimeout](https://msdn.microsoft.com/library/System.Data.Common.DBCommand.CommandTimeout) value.\r\n\r\n## Modifying data\r\n\r\n```cs\r\nquery.Change(\"DELETE FROM Users WHERE Name LIKE @NameToDelete\", new { NameToDelete = \"John\" });\r\n```\r\n\r\nYou can also make sure how many rows will be affected with:\r\n\r\n* `ChangeExactly(n, sql, parameters)`\r\n* `ChangeNoLessThan(n, sql, parameters)`\r\n* `ChangeNoMoreThan(n, sql, parameters)`\r\n\r\n`UnexpectedNumberOfRowsAffectedException` is thrown and the transaction is rolled back if the amount of affected rows is\r\ndifferent from the expected.\r\n\r\n## Retrieving data\r\n\r\n```cs\r\nint count = query.SelectSingle\u003cint\u003e(\"SELECT COUNT(0) FROM Users\");\r\n\r\nDataTable dataTable = query.Select(\"SELECT * FROM Users\");\r\n\r\nIEnumerable\u003cUser\u003e users = query.Select\u003cUser\u003e(\"SELECT * FROM Users\");\r\nUser user = query.SelectExactlyOne\u003cUser\u003e(\"SELECT * FROM Users WHERE Id = @Id\", new { Id = 1337 });\r\n```\r\n\r\nYou can also make sure how many rows will be selected with:\r\n\r\n* `SelectExactly(n, sql, parameters)`\r\n* `SelectNoLessThan(n, sql, parameters)`\r\n* `SelectNoMoreThan(n, sql, parameters)`\r\n\r\n`UnexpectedNumberOfRowsSelectedException` is thrown if the amount of selected rows is different from the expected.\r\n\r\n## Behind the covers\r\n\r\n`Change` uses [SqlCommand.ExecuteNonQuery](https://msdn.microsoft.com/library/System.Data.SqlClient.SqlCommand.ExecuteNonQuery),\r\n`Select` uses [DbDataAdapter.Fill](https://msdn.microsoft.com/library/System.Data.Common.DbDataAdapter.Fill)\r\n(except `SelectSingle`, which uses [SqlCommand.ExecuteScalar](https://msdn.microsoft.com/library/System.Data.SqlClient.SqlCommand.ExecuteScalar)).\r\n\r\n## Thread safety\r\n\r\nThe library isn't thread safe, but it should be lightweight enough to be instantiated as needed during the lifetime of\r\nyour application (such as one per request).\r\n\r\n## Connections and Transactions\r\n\r\nThe library opens a connection (and a transaction for writes) and closes it for every operation.\r\nThere's no need to call [Dispose](https://msdn.microsoft.com/library/System.IDisposable.Dispose).\r\n\r\n```cs\r\nvar query = new Query(\"connection string\", \"provider name\"); // false is the default for manualClosing\r\n\r\n// opens and closes a connection and a transaction\r\nquery.Change(\"INSERT INTO Foo VALUES ('Bar')\");\r\n\r\n// opens and closes a connection (again)\r\n// 'Foo' will have 'Bar' in the database, despite the exception here\r\nquery.Change(\"some syntax error\");\r\n```\r\n\r\nHowever, if `manualClosing` is set to `True`, it automatically opens the connection and transaction and reuses it for\r\neach consecutive command.\r\nThe open connection and (and transaction) are closed/committed when you call `Close()`.\r\n\r\n```cs\r\nvar query = new Query(\"connection string\", \"provider name\", manualClosing: true);\r\n\r\n// opens a connection and a transaction\r\nquery.Change(\"INSERT INTO Foo VALUES ('Bar')\");\r\n\r\n// reuses the connection (and transaction) opened above\r\n// 'Foo' won't have 'Bar' in the database, the exception here rollbacks the transaction\r\nquery.Change(\"some syntax error\");\r\n\r\n// commits the transaction and closes the connection\r\n// (won't reach here in this particular example because the line above raised an exception and rolled back)\r\nquery.Close();\r\n```\r\n\r\nIf you don't plan to reuse the object elsewhere, you may shield its usage with `using`:\r\n\r\n```cs\r\n// this is equivalent to the example above\r\nusing (var query = new Query(\"connection string\", \"provider name\", manualClosing: true))\r\n{\r\n    query.Change(\"INSERT INTO Foo VALUES ('Bar')\");\r\n    query.Change(\"some syntax error\");\r\n}\r\n```\r\n\r\n## IN clauses\r\n\r\nThe library automatically prepares collections ([IEnumerable](https://msdn.microsoft.com/library/System.Collections.IEnumerable))\r\nfor [IN](https://msdn.microsoft.com/library/ms177682) clauses\r\n([taking that burden off you](http://stackoverflow.com/q/337704/1316620)).\r\n\r\nThis:\r\n\r\n```cs\r\nquery.Change(\"DELETE FROM Users WHERE Id IN (@Ids)\", new { Ids = new[] { 1, 123, 44 } });\r\n```\r\n\r\nBecomes this:\r\n\r\n```sql\r\nDELETE FROM Users WHERE Id IN (@Ids0, @Ids1, @Ids2)\r\n```\r\n\r\n## SELECT clauses\r\n\r\nRunning handmade SQL queries instead of fighting an ORM to find out what it's generating is one of the reasons to use a\r\n*micro ORM*.\r\n\r\nIt's all fun and games until you have to build a more complex query, one that can take multiple forms accordingly to\r\nsome set of parameters.\r\n\r\nThose are usually `SELECT` queries in which the `WHERE` clause can take different combinations of parameters (or even be\r\nabscent).\r\n\r\nTo aid in such scenarios, there is a built-in `Select` type that you can instantiate it like\r\n`new Select(\"ColumnA\", \"ColumnB\", \"ColumnC\", ...)` and then, on the constructed object, you're able to call:\r\n\r\n* `From`\r\n* `Join`\r\n* `LeftOuterJoin`\r\n* `RightOuterJoin`\r\n* `FullOuterJoin`\r\n* `CrossJoin`\r\n* `Where`\r\n* `WhereAnd`\r\n* `WhereOr`\r\n* `GroupBy`\r\n* `Having`\r\n* `OrderBy`\r\n\r\nA `ToString` call gives you the resulting SQL (but the object implicitly casts to string if needed).\r\n\r\nTo illustrate, such page:\r\n\r\n![](Images/screen.png)\r\n\r\nCould be powered by the following code:\r\n\r\n```cs\r\npublic class Role\r\n{\r\n    public int Id { get; set; }\r\n\r\n    public string Name { get; set; }\r\n}\r\n\r\npublic class User\r\n{\r\n    public int Id { get; set; }\r\n\r\n    public string Name { get; set; }\r\n\r\n    public string Email { get; set; }\r\n\r\n    // this property requires a JOIN when querying the database\r\n    public Role Role { get; set; }\r\n}\r\n\r\n// it's often useful to expose the Query object through a property\r\nQuery Query\r\n{\r\n    get =\u003e new Query(\"connection string\", \"provider name\");\r\n}\r\n\r\n// it's also useful to create a property with a 'vanilla' SELECT of an entity of yours (DRY)\r\nSelect UserSelect\r\n{\r\n    get =\u003e new Select(\r\n        // the names of the selected columns and the class properties must match\r\n        \"User.Id\",\r\n        \"User.Name\",\r\n        \"User.Email\",\r\n\r\n        // it can work out the whole property tree, in other words, it can go more than one level deeper\r\n        // (PropertyA.PropertyAB.PropertyABC.PropertyABCD...)\r\n        \"Role.Id AS 'Role.Id'\",\r\n        \"Role.Name AS 'Role.Name'\")\r\n        .From(\"User\")\r\n        .Join(\"Role\", \"RoleId = Role.Id\");\r\n}\r\n\r\n// a search method in which all the parameters are optional\r\nIEnumerable\u003cUser\u003e Search(string name, string email, int? role)\r\n{\r\n    var select = UserSelect;\r\n\r\n    // using a ExpandoObject as parameters helps when dealing with optional conditions\r\n    dynamic parameters = new ExpandoObject();\r\n\r\n    if (!string.IsNullOrWhiteSpace(name))\r\n    {\r\n        select.WhereAnd(\"User.Name LIKE %@Name%\");\r\n        parameters.Name = name;\r\n    }\r\n\r\n    if (!string.IsNullOrWhiteSpace(email))\r\n    {\r\n        select.WhereAnd(\"User.Email LIKE %@Email%\");\r\n        parameters.Email = email;\r\n    }\r\n\r\n    if (role.HasValue)\r\n    {\r\n        select.WhereAnd(\"User.RoleId = @RoleId\");\r\n        parameters.Role = role;\r\n    }\r\n\r\n    return Query.Select\u003cUser\u003e(select, parameters);\r\n}\r\n```","funding_links":[],"categories":["C\\#"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftallesl%2Fnet-Query","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftallesl%2Fnet-Query","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftallesl%2Fnet-Query/lists"}