{"id":17695804,"url":"https://github.com/haath/quermine","last_synced_at":"2026-04-09T17:49:07.147Z","repository":{"id":137159844,"uuid":"127560324","full_name":"haath/Quermine","owner":"haath","description":"Query-free integration with relational databases in an object-oriented manner.","archived":false,"fork":false,"pushed_at":"2019-04-30T08:32:09.000Z","size":258,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-27T19:03:34.183Z","etag":null,"topics":["database","mysql","nuget","relational-databases","serializer","sql-server"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haath.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":"2018-03-31T18:35:52.000Z","updated_at":"2019-04-30T08:32:10.000Z","dependencies_parsed_at":null,"dependency_job_id":"dc96ba07-fd44-486d-aa80-e64c344e4ba3","html_url":"https://github.com/haath/Quermine","commit_stats":null,"previous_names":["gmantaos/quermine"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/haath/Quermine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haath%2FQuermine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haath%2FQuermine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haath%2FQuermine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haath%2FQuermine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haath","download_url":"https://codeload.github.com/haath/Quermine/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haath%2FQuermine/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267527835,"owners_count":24102019,"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","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"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":["database","mysql","nuget","relational-databases","serializer","sql-server"],"created_at":"2024-10-24T14:07:00.697Z","updated_at":"2025-12-30T21:57:24.291Z","avatar_url":"https://github.com/haath.png","language":"C#","funding_links":["https://ko-fi.com/D1D7NYV3'"],"categories":[],"sub_categories":[],"readme":"\n\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"Assets/logo.png\"\u003e\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://ci.appveyor.com/project/gmantaos/quermine\"\u003e\u003cimg src=\"https://ci.appveyor.com/api/projects/status/ahda4q6d648ahq99/branch/master?svg=true\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.nuget.org/packages/Quermine\"\u003e\u003cimg src=\"https://img.shields.io/nuget/v/Quermine.svg?logo=%20data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAACzVBMVEWUlJSSk5QAAACTlJSUlJSUlJSUlJSSk5STlJSUlJSUlJSQkJSUlJSVlJSTlJSUlJSWlJSUlJSUlJSUlJSUlJSUlJSUlJSSk5SUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSVlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSSk5OUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSTlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSRlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJT////89+1nAAAA5nRSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGRjynN/7EL/d4evv2jCBxkZhgHKUtVVVVVSCQFATqo5/r9/f3545spU+TRNi7d0qC++MQdAI+5IAyJ/vx8Es7+UyXkxybn/FIk4+ks7LQZCIH97Czr/ciRtPXs9821yfXlYRIFD1ba9l1K7yzsxQ8HsirqogGK7BvbtwgCotoGrOs9LuGdUfXDMQIBKLnkPAeN/OKbe5bc9WwBDX3l/v3bZAYDNoSyvby9rncqAaFB9roAAAABYktHRO7Pt9I3AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gkcECYepXCHSAAAAXJJREFUKM9jsLC0smZgZMIADDa2z+zsmbFIODx/4ejEgkXC2eWlqxsrFgl3D08vNnYOTm8fXz9/IAgIDAoO4eJmYgBL84SGhUdERkWDQExsXHwCLx9Ygl8gMekVArx4nZwiCJYQSk17k56RmYWQy84BSQjn5r3OLxApLCqGS5SUgiREy8orKsXEJaqqX8BlakASkrV19Q1S0jKNTQizmkESsi2tr9ra5To6uxAS3SAJ+Z7eV339EyZOgjoKREyGSbx69RosOmXqtOkzUCXAYOas2XPmzpuPIbFgoYIik5LyosVQiSVLoRLLlqsA+aorVkIk1FathkqsWasO5Gtornu7HiShtWEj1GebNmsD+Tpbtr7aBpLQ3b4DqmPnLj19JgPD3Xte7wXbYbRvP1TmwMFDxoePHH117Dg4dE1OnDwFNez0mbPnzr++cPESJKJML1+5eg0i8/r16+s3bt4yg0gwmd++c/fe/Qcg8PDR4ydPOZgAdroNuedFNaIAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTgtMDktMjhUMTY6Mzg6MzAtMDQ6MDDaPYBtAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE4LTA5LTI4VDE2OjM4OjMwLTA0OjAwq2A40QAAAABJRU5ErkJggg==\"\u003e\u003c/a\u003e\n\u003ca href=\"https://www.nuget.org/packages/Quermine\"\u003e\u003cimg src=\"https://img.shields.io/nuget/dt/Quermine.svg?logo=%20data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAACzVBMVEWUlJSSk5QAAACTlJSUlJSUlJSUlJSSk5STlJSUlJSUlJSQkJSUlJSVlJSTlJSUlJSWlJSUlJSUlJSUlJSUlJSUlJSUlJSSk5SUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSVlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSSk5OUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSTlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSRlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSTlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJT////89+1nAAAA5nRSTlMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGRjynN/7EL/d4evv2jCBxkZhgHKUtVVVVVSCQFATqo5/r9/f3545spU+TRNi7d0qC++MQdAI+5IAyJ/vx8Es7+UyXkxybn/FIk4+ks7LQZCIH97Czr/ciRtPXs9821yfXlYRIFD1ba9l1K7yzsxQ8HsirqogGK7BvbtwgCotoGrOs9LuGdUfXDMQIBKLnkPAeN/OKbe5bc9WwBDX3l/v3bZAYDNoSyvby9rncqAaFB9roAAAABYktHRO7Pt9I3AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gkcECYepXCHSAAAAXJJREFUKM9jsLC0smZgZMIADDa2z+zsmbFIODx/4ejEgkXC2eWlqxsrFgl3D08vNnYOTm8fXz9/IAgIDAoO4eJmYgBL84SGhUdERkWDQExsXHwCLx9Ygl8gMekVArx4nZwiCJYQSk17k56RmYWQy84BSQjn5r3OLxApLCqGS5SUgiREy8orKsXEJaqqX8BlakASkrV19Q1S0jKNTQizmkESsi2tr9ra5To6uxAS3SAJ+Z7eV339EyZOgjoKREyGSbx69RosOmXqtOkzUCXAYOas2XPmzpuPIbFgoYIik5LyosVQiSVLoRLLlqsA+aorVkIk1FathkqsWasO5Gtornu7HiShtWEj1GebNmsD+Tpbtr7aBpLQ3b4DqmPnLj19JgPD3Xte7wXbYbRvP1TmwMFDxoePHH117Dg4dE1OnDwFNez0mbPnzr++cPESJKJML1+5eg0i8/r16+s3bt4yg0gwmd++c/fe/Qcg8PDR4ydPOZgAdroNuedFNaIAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTgtMDktMjhUMTY6Mzg6MzAtMDQ6MDDaPYBtAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE4LTA5LTI4VDE2OjM4OjMwLTA0OjAwq2A40QAAAABJRU5ErkJggg==\"\u003e\u003c/a\u003e\n\u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\"\u003e\u003c/a\u003e\n\n\u003c/p\u003e\n\nThis library offers a significant abstraction over integrating with a relational database in your **.NET** application. What started out as a personal wrapper for convenient async operations and MySql type conversions later became an intuitive query builder and object serializer. With this library you easily connect your classes with your database tables in minutes and without writing almost any queries.\n\nThese abstractions aren't always free however, you cannot use the chain query building and serialization features of this library to create highly efficient queries, with complex join operations. For these cases you are still better off compiling your own. But in every other case, where you simply want to deal database tables as if they were nothing more than classes, fetching, updating and storing them again as you please, then Quermine has you covered.\n\nThe goals of this library are:\n\n- To provide a uniform plug n' play solution for dealing with your database in an object-oriented way.\n- To build your queries in a LINQ-like chaining manner, instead of with messy string injections and appendages.\n- Query-free integration with relational databases for the everyday simple object-oriented cases.\n- Painless extension for additional DBMS connectors and syntaxes.\n\n#### Progress\n\n- [x] MySql\n- [x] Sqlite\n- [x] SQL Server\n- [ ] PostgreSql\n\n## Installation\n\nGet the appropriate package from NuGet\n\n- [Quermine.MySql](https://www.nuget.org/packages/Quermine.MySql)\n- [Quermine.Sqlite](https://www.nuget.org/packages/Quermine.Sqlite)\n- [Quermine.SqlServer](https://www.nuget.org/packages/Quermine.SqlServer)\n\n## Usage\n\nAll of the connection objects shown below extend `DbClient` and have an almost identical API.\n\n### MySql\n\n```csharp\nusing Quermine;\nusing Quermine.MySql;\n\nMySqlConnectionInfo info = new MySqlConnectionInfo(\"127.0.0.1\", \"root\", \"password\", \"database\");\n\n// You can also add additional values to the connection string\ninfo.AddParameter(\"charset\", \"utf8\")\n    .AddParameter(\"Allow Zero Datetime\", \"True\");\n\nusing (MySqlClient connection = await info.Connect())\n{\n    ...\n}\n```\n\n### Sqlite\n\n```csharp\nusing Quermine;\nusing Quermine.Sqlite;\n\nSqliteConnectionInfo info = new SqliteConnectionInfo(\"/var/www/mydb.sqlite\");\n\nusing (SqliteClient connection = await info.Connect())\n{\n    ...\n}\n```\n\nOr if the database file doesn't exist yet.\n\n```csharp\nSqliteConnectionInfo info = new SqliteConnectionInfo(\"/var/www/mydb.sqlite\");\n\ninfo.Create();\n```\n\n### SQL Server\n\n```csharp\nusing Quermine;\nusing Quermine.SqlServer;\n\nSqlServerConnectionInfo info = new SqlServerConnectionInfo(\"127.0.0.1\", \"root\", \"password\", \"database\");\n\n// You can also add additional values to the connection string\ninfo.AddParameter(\"Integrated Security\", \"True\");\n\nusing (SqlServerClient connection = await info.Connect())\n{\n    ...\n}\n```\n\n## Queries\n\nThe following examples will be using MySql, but the usage will be identical to that of the other supported types. You can of course write your own queries, like you normally would. In this case you would be taking advantage of the library's wrappers.\n\n```csharp\n\nQuery q = QueryProvider.Query(\"SELECT * FROM cats WHERE color=@color\");\n\nq.AddParameter(\"@color\", \"orange\");\n\nq.OnRow += (s, row) =\u003e {\n\n    // Getting rows as events when they arrive.\n    row.GetString(\"name\");\n    row.GetInteger(\"age\");\n    row.GetBoolean(\"gender\");\n    \n};\n \n// Or get the whole result set once the query is completed.\nResultSet result = await connection.Execute(q);\n\nforeach (ResultRow row in result)\n{\n    ...\n}\n```\n\n### NonQueries\n\n```csharp\nQuery q = QueryProvider.Query(\"DELETE FROM cats WHERE color='orange'\");\n\nNonQueryResult result = await connection.ExecuteNonQuery(q);\n\nresult.RowsAffected;\nresult.LastInsertedId;\n```\n\n### Transactions\n\n```csharp\nQuery q1, q2, q3;\n\nList\u003cNonQueryResult\u003e result = await connection.ExecuteTransaction(q1, q2, q3);\n\n// The transaction was committed \nforeach (NonQueryResult r in result)\n{\n    // The result of each query in the order they were executed\n}\n```\n\nA failing transaction will throw the exception that was raised.\n\n```csharp\ntry\n{\n\tawait connection.ExecuteTransaction(q1, q2, q3);\n}\ncatch(Exception ex)\n{\n\t// Transaction was rolled-back automatically\n\tConsole.WriteLine(ex);\n}\n```\n\n### Schemas\n\n```csharp\nList\u003cstring\u003e tables = await connection.GetTableNames();\n\nforeach (string table in tables)\n{\n    TableSchema schema = await connection.GetTableSchema(table);\n\n    // Get specific fields by name\n    TableField nameField = schema[\"name\"];\n\n    // ... or iterate over them\n    foreach (TableField field in schema)\n    {\n        ...\n    }\n}\n```\n\n## Chaining\n\n\n### Select\n\n```csharp\nSelectQuery q = QueryProvider.Select();\n\nq.Select(\"name\", \"age\")\n .From(\"tableName\")\n .Where(\"age\", WhereRelation.LesserThan, 10)\n .Where(\"name\", WhereRelation.Like, \"John%\")\n .Where(\"email\", ColumnCondition.IsNull)\n .Limit(5)\n .Offset(10);\n\nawait connection.Execute(q);\n```\n\n### Insert\n\n```csharp\nInsertQuery q = QueryProvider.Insert(\"table_name\");\n\nq.Value(\"user_id\", 4)\n .Value(\"age\", 10)\n .Value(\"timestamp\", DateTime.Now);\n \nawait connection.ExecuteNonQuery(q);\n```\n\n### Delete\n\n```csharp\nDeleteQuery q = QueryProvider.Delete(\"table_name\");\n\nq.Where(\"id\", 2); // Shortcut to Where(\"id\", WhereRelation.Equal, 2)\n\nawait connection.ExecuteNonQuery(q);\n```\n\n#### WHERE clause\n\n##### Chaining appends logical AND\n\n```csharp\nq.Where(\"age\", WhereRelation.LesserThan, 10)\n .Where(\"name\", WhereRelation.Like, \"John%\");\n```\n\nWill result in...\n\n```mysql\nWHERE age \u003c 10 AND name LIKE 'John%'\n```\n\n##### To create nested and/or logical OR conditions create them manually\n\n```csharp\nq.Where(\n    new WhereClause(\"age\", WhereRelation.LesserThan, 10)\n    | new WhereClause(\"name\", WhereRelation.Like, \"John%\")\n);\n```\n\nWill result in\n\n```mysql\nWHERE age \u003c 10 OR name like 'John%'\n```\n\nNesting works as well\n\n```csharp\nWhereClause w1, w2, w3, w4;\n\nq.Where(\n    (w1 | w2) \u0026 (w3 \u0026 w4)\n);\n```\n\n## Serialization\n\n```csharp\n[DbTable(\"people\")]\nclass Person\n{\n    [DbField(\"name\")]\n    string Name;\n\n    [DbField(\"age\")]\n    int Age;\n}\n```\n\nYou can deserialize any query into your object.\n\n```csharp\nQuery q = QueryProvider.Query(\"SELECT name, age FROM other_table\");\n\nList\u003cPerson\u003e people = await connection.Execute\u003cPerson\u003e(q);\n```\n\nOr you can let the library construct the queries, as shown in the sections below.\n\n### Inserting\n\n```csharp\nPerson p = new Person(name: \"John\", age: 42);\n\nconnection.Insert\u003cPerson\u003e(p);\n```\n\nOr if you want to add parameters...\n```csharp\nPerson p = ...;\n\nInsertQuery\u003cPerson\u003e q = MyQueryProvider.Insert\u003cPerson\u003e(p);\n\n// Turn it into a REPLACE query\np.Replace();\n\n// Or an INSERT IGNORE INTO\np.Ignore();\n\nawait connection.ExecuteNonQuery(q);\n```\n\n### Selecting\n\n```csharp\nList\u003cPerson\u003e = await connection.Select\u003cPerson\u003e();\n```\n\nOr if you want to add parameters...\n```csharp\nSelectQuery\u003cPerson\u003e q = QueryProvider.Select\u003cPerson\u003e();\n\nq.Where(\"name\", Comparison.Equals, \"John\");\n\nList\u003cPerson\u003e result = awat connection.ExecuteNonQuery(q);\n```\n\n### Deleting\n\n**WARNING**: `DeleteQuery` will delete ANY rows that match the given object's values.\n\n```csharp\nPerson p = new Person(name: \"John\", age: 42);\n\nconnection.Delete\u003cPerson\u003e(p);\n```\n\n### Updating\n\n```csharp\nPerson john = new Person(name: \"John\", age: 42);\n\nawait connection.Update\u003cPerson\u003e(john, p =\u003e {\n\n    //Whatever happens to the object in this lambda will also happen to it in the database\n\n    p.Age  = 10;\n\n});\n\n/*\nNow john.Age is 10 and john's age in the databse is also 10\n*/\n```\n\n### Creating tables\n\n##### `This is a v2.0 feature which has not yet been released`\n\n```csharp\nawait client.DropTableIfExists(\"people\");\n\nawait client.CreateTable\u003cPerson\u003e();\n```\n\n### Ignoring fields\n\n##### `This is a v2.0 feature which has not yet been released`\n\nThere are cases when certain fields should participate in `SELECT` queries, for retrieving objects, \nbut not in other kinds of queries. Such cases for example are the following:\n\n- **Auto-Increment IDs**: A field mapped to such a column in a table should generally not be specified manually when inserting an object, or attempted to be updated. To achieve this you can use the `InsertIgnore` and `UpdateIgnore` attributes.\n- **Non-Distinctive Types:** Queries like `DELETE`, `UPDATE` and `SELECT` should use distinctive fields of an object in their `WHERE` clauses, like an ID or a name. Searching by values that don't define the object or values that are hard to compare - like floating point numbers for example - can lead to unintended side effects. To exclude such fields from `WHERE` clauses use the `WhereIgnore` attribute.\n\n```csharp\n[DbTable(\"people\")]\nclass Person\n{\n    [DbField(\"id\"), InsertIgnore, UpdateIgnore]\n    int ID;\n\n    [DbField(\"name\")]\n    string Name;\n\t\n    [DbField(\"savings\"), WhereIgnore]\n    double Savings;\n}\n```\n\n### Custom value formatting\n\n##### `This is a v2.0 feature which has not yet been released`\n\nAnother common use case is having to convert or transform values, between serializable members and the database. Such instances may require a simple type cast, or even custom parsing of the given values to generate entirely new objects. To achieve this, you can create custom formatters that implement the `IValueFormatter\u003cT\u003e` interface, like in the following examples.\n\n```csharp\n// Treating an integer in the database as a double in the object\nclass RoundFormatter : IValueFormatter\u003cdouble\u003e\n{\n    public object GetValue(double val)\n    {\n        return (int)Math.Round(val);\n    }\n\n    public double SetValue(object val)\n    {\n        return (double)val;\n    }\n}\n\n// Treating a string field in the database as a byte array in the object\nclass AsciiFormatter : IValueFormatter\u003cbyte[]\u003e\n{\n    public object GetValue(byte[] val)\n    {\n        return Encoding.ASCII.GetString(val);\n    }\n\n    public byte[] SetValue(object val)\n    {\n        return Encoding.ASCII.GetBytes(val.ToString());\n    }\n}\n\n// Having a birthday in the database but wanting an age in the class\nclass AgeFormatter : IValueFormatter\u003cint\u003e\n{\n    public object GetValue(int val)\n    {\n        throw new NotImplementedException();\n    }\n\n    public int SetValue(object val)\n    {\n        DateTime birthday = (DateTime)val;\n\t\n        return YearsBetween(birthday, DateTime.Now);\n    }\n}\n```\n\n`GetValue` is used when *reading* the value of a member, in order to place the converted value in a query, and `SetValue` is used to convert values fetched from the database before *writing* them on the member.\n\n```csharp\n[DbTable(\"books\")]\nclass Book\n{\n    [DbField(\"description\", FormatWith = typeof(AsciiFormatter))]\n    byte[] AsciiDescription;    // a string in the database\n    \n    [DbField(\"savings\", FormatWith = typeof(RoundFormatter))]\n    double Savings;             // an integer in the database\n    \n    [DbField(\"release_date\", FormatWith = typeof(AgeFormatter))]\n    int Age;\t\t\t// a DateTime in the database\n}\n```\n\n## Known issues and limitations\n\n#### SQL Server\n\n- The `LastInsertedId` field on non-query results will always return `-1`, since implementing it would require injecting things into queries. If and and how this should happen needs to be carefully looked into beforehand.\n- The `AutoIncrement`, `Unsigned`, `Zerofill` and `Key` fields of a `TableField` will be non-indicative of the real value.\n\n#### SQLite\n\n- The `AutoIncrement` and `NotNull` fields of a `TableField` will be non-indicative of the real value.\n\n---\n\n\u003cp align=\"center\"\u003e\n\u003ca href='https://ko-fi.com/D1D7NYV3' target='_blank'\u003e\u003cimg height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi2.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /\u003e\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaath%2Fquermine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaath%2Fquermine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaath%2Fquermine/lists"}