{"id":13431322,"url":"https://github.com/henkmollema/Dommel","last_synced_at":"2025-03-16T11:31:27.434Z","repository":{"id":17940909,"uuid":"20919738","full_name":"henkmollema/Dommel","owner":"henkmollema","description":"CRUD operations with Dapper made simple.","archived":false,"fork":false,"pushed_at":"2024-11-15T13:02:28.000Z","size":2611,"stargazers_count":662,"open_issues_count":9,"forks_count":104,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-03-05T02:16:04.960Z","etag":null,"topics":["crud","dapper","dommel","micro-orm","query-builder","sql-expression"],"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/henkmollema.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":"2014-06-17T10:45:02.000Z","updated_at":"2025-02-26T16:07:54.000Z","dependencies_parsed_at":"2024-02-06T12:52:56.029Z","dependency_job_id":"cc55df15-420a-448a-88bb-f89bdfdabf9d","html_url":"https://github.com/henkmollema/Dommel","commit_stats":{"total_commits":375,"total_committers":25,"mean_commits":15.0,"dds":"0.17333333333333334","last_synced_commit":"16e009824ad5377e3f993711d7a139a930466e49"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henkmollema%2FDommel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henkmollema%2FDommel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henkmollema%2FDommel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/henkmollema%2FDommel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/henkmollema","download_url":"https://codeload.github.com/henkmollema/Dommel/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243862889,"owners_count":20360233,"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":["crud","dapper","dommel","micro-orm","query-builder","sql-expression"],"created_at":"2024-07-31T02:01:02.230Z","updated_at":"2025-03-16T11:31:27.421Z","avatar_url":"https://github.com/henkmollema.png","language":"C#","funding_links":[],"categories":["Frameworks, Libraries and Tools","C\\#","others","框架, 库和工具","ORM"],"sub_categories":["ORM","对象关系映射ORM"],"readme":"# Dommel\nCRUD operations with Dapper made simple.\n\n| Build | NuGet | MyGet | Test Coverage |\n| ----- | ----- | ----- | ------------- |\n| [![Travis](https://img.shields.io/travis/com/henkmollema/Dommel?style=flat-square)](https://app.travis-ci.com/github/henkmollema/Dommel) | [![NuGet](https://img.shields.io/nuget/vpre/Dommel.svg?style=flat-square)](https://www.nuget.org/packages/Dommel) | [![MyGet Pre Release](https://img.shields.io/myget/dommel-ci/vpre/Dommel.svg?style=flat-square)](https://www.myget.org/feed/dommel-ci/package/nuget/Dommel) | [![codecov](https://codecov.io/gh/henkmollema/Dommel/branch/master/graph/badge.svg)](https://codecov.io/gh/henkmollema/Dommel) |\n\n\u003chr\u003e\n\nDommel provides a convenient API for CRUD operations using extension methods on the `IDbConnection` interface. The SQL queries are generated based on your POCO entities. Dommel also supports LINQ expressions which are being translated to SQL expressions. [Dapper](https://github.com/StackExchange/Dapper) is used for query execution and object mapping.\n\nThere are several extensibility points available to change the behavior of resolving table names, column names, the key property and POCO properties. See [Extensibility](https://github.com/henkmollema/Dommel#extensibility) for more details.\n\n## Installing Dommel\n\nDommel is available on [NuGet](https://www.nuget.org/packages/Dommel).\n\n### Install using the .NET CLI:\n```\ndotnet add package Dommel\n```\n\n### Install using the NuGet Package Manager:\n```\nInstall-Package Dommel\n```\n\n## Using Dommel\n\n### Retrieving entities by ID\n```cs\nvar product = await connection.GetAsync\u003cProduct\u003e(1);\n```\n\n### Retrieving all entities in a table\n```cs\nvar products = await connection.GetAllAsync\u003cProduct\u003e();\n```\n\n### Selecting entities using a predicate\nDommel allows you to specify a predicate which is being translated into a SQL expression. The arguments in the lambda expression are added as parameters to the command.\n```cs\nvar products = await connection.SelectAsync\u003cProduct\u003e(p =\u003e p.Name == \"Awesome bike\" \u0026\u0026 p.Created \u003c new DateTime(2014, 12, 31) \u0026\u0026 p.InStock \u003e 5);\n```\n\nWhich would translate in the following SQL:\n```sql\nselect * from Products where Name = @p1 and Created \u003c @p2 and InStock \u003e @p3\n```\n\nYou can add parentheses to combine `and` \u0026 `or` queries:\n```cs\nvar products = await connection.SelectAsync\u003cProduct\u003e(p =\u003e p.Name == \"Awesome bike\" \u0026\u0026 (p.Created \u003c new DateTime(2014, 12, 31) || p.InStock \u003e 5));\n```\n\nWhich would translate in the following SQL:\n```sql\nselect * from Products where Name = @p1 and (Created \u003c @p2 or InStock \u003e @p3)\n```\n\nThere is also a `FirstOrDefaultAsync\u003cT\u003e(...)` method available to select the first entity matching the predicate.\n\n#### Like-queries\nIt is possible to generate `LIKE`-queries using `Contains()`, `StartsWith()` or `EndsWith()` on string properties:\n\n```cs\nvar products = await connection.SelectAsync\u003cProduct\u003e(p =\u003e p.Name.Contains(\"bike\"));\nvar products = await connection.SelectAsync\u003cProduct\u003e(p =\u003e p.Name.StartsWith(\"bike\"));\nvar products = await connection.SelectAsync\u003cProduct\u003e(p =\u003e p.Name.EndsWith(\"bike\"));\n```\n\n### Inserting entities\n```cs\nvar product = new Product { Name = \"Awesome bike\", InStock = 4 };\nvar id = await connection.InsertAsync(product);\n```\n\n### Updating entities\n```cs\nvar product = await connection.GetAsync\u003cProduct\u003e(1);\nproduct.Name = \"New name\";\nawait connection.UpdateAsync(product);\n```\n\n### Removing entities\n```cs\nvar product = await connection.GetAsync\u003cProduct\u003e(1);\nawait connection.DeleteAsync(product);\n```\n\n### Multi mapping\n\n#### One-to-one relations\n\nDommel is able to generate join-queries based on the specified multi mapping function. Consider the following POCO's:\n\n```cs\npublic class Product\n{\n    public int Id { get; set; }\n\n    public string Name { get; set; }\n\n    // Maps to the foreign key column\n    public int CategoryId { get; set; }\n\n    // The navigation property\n    public Category Category { get; set; }\n}\n\n\npublic class Category\n{\n    public int Id { get; set; }\n\n    public string Name { get; set; }\n}\n```\n\nThe `Product` with its associated `Category` can be queried toegether using the `Get\u003cT1, T2, ..., TResult\u003e()` method:\n\n```cs\nvar product = await product.GetAsync\u003cProduct, Category, Product\u003e(1, (product, category) =\u003e\n{\n    product.Category = category;\n    return product;\n});\n```\n\n##### Foreign key columns\n\n`CategoryId` is automatically used as foreign key between `Product` and `Category`. This follows a simple convention: joining table name + `Id` (`Category` + `Id`). You can override this behavior by using the `[ForeignKey(\"ForeignKeyColumnName\")]` attribute or by implementing your own `IForeignKeyPropertyResolver`.\n\n#### One-to-many relations\n\nOne-to-many relationships work in a similar way, expect that the foreign key is defined on the _joined_ type rather than the _source_ type. For example:\n\n```cs\npublic class Order\n{\n    public int Id { get; set; }\n\n    // The navigation property\n    public ICollection\u003cOrderLine\u003e OrderLines { get; set; } = new List\u003cOrderLine\u003e();\n}\n\npublic class OrderLine\n{\n    public int Id { get; set; }\n\n    // The foreign key column to the Order table\n    public int OrderId { get; set; }\n\n    public string Description { get; set; }\n}\n```\n\nThe `Order` with its child `OrderLine`'s can be queried toegether using the `Get\u003cT1, T2, ..., TResult\u003e()` method:\n\n```cs\nvar product = await product.GetAsync\u003cOrder, OrderLine, Order\u003e(1, (order, line) =\u003e\n{\n    // Naive mapping example, in reality it requires more gymnastics\n    order.OrderLines.Add(line);\n    return order;\n});\n```\n\n### Automatic multi mapping\n\n\u003e Note: this is an experimental feature.\n\nDommel is able to create simple join-expressions for retrieving parent-child entities. One-to-one and one-to-many relations are supported. It works the samy way as regular mapping, except there is no need to specify a function which performs the mapping of the objects. Using the same POCO's as the previous examples:\n\nRetrieving a `Product` and its associated `Category`:\n\n```cs\nvar product = product.Get\u003cProduct, Category, Product\u003e(1);\n```\n\nRetrieving one `Order` and with its child `OrderLine`'s:\n\n```cs\nvar product = product.Get\u003cOrder, OrderLine, Order\u003e(1);\n```\n\n#### Entity equality\nWhen joining with two or more tables with a one-to-many relationship, you are required to override `Equals(object obj)` method or implement the `IEquatable\u003cT\u003e` interface on your POCO's so Dommel can determine whether an entity is already added to the collection. For example:\n\n```cs\npublic class OrderLine : IEquatable\u003cOrderLine\u003e\n{\n    public int Id { get; set; }\n\n    public int OrderId { get; set; }\n\n    public string Description { get; set; }\n\n    public bool Equals(OrderLine other) =\u003e Id == other.Id;\n}\n```\n\n### Combining `Select` and multi-mapping\nIt's possible to combine `Select` queries and multi-mapping. For example:\n```cs\nvar products = await connection.SelectAsync\u003cProduct, Category, Product\u003e(x =\u003e x.Name.StartsWith(\"bike\"));\n```\nThis is applicable for `Select`, `SelectAsync`, `FirstOrDefault` and `FirstOrDefaultAsync`. Both with manual and automatic multi-mapping.\n\n### From-queries\nWith `From`-queries you can create more complex queries on a certain table by providing access to the `SqlExpression\u003cT\u003e`. For example:\n```cs\nvar products = await connection.FromAsync\u003cProduct\u003e(sql =\u003e sql\n    .Where(x =\u003e x.Name.StartsWith(\"bike\") \u0026\u0026 x.DeletedOn == null)\n    .OrWhere(x =\u003e x.InStock \u003e 5)\n    .OrderBy(x =\u003e x.DateCreated)\n    .Page(1, 25)\n    .Select()));\n```\n\n## Async and non-async\nAll Dommel methods have async and non-async variants, such as as `Get` \u0026 `GetAsync`, `GetAll` \u0026 `GetAllAsync`, `Select` \u0026 `SelectAsync`, `Insert` \u0026 `InsertAsync`, `Update` \u0026 `UpdateAsync`, `Delete` \u0026 `DeleteAsync`, etc.\n\n## Query builders\n\nDommel supports building specialized queries for a certain RDBMS. By default, query builders for the following RDMBS are included: SQL Server, SQL Server CE, SQLite, MySQL and Postgres. The query builder to be used is determined by the connection type. To add or overwrite an existing query builder, use the `AddSqlBuilder()`  method:\n\n```cs\nDommelMapper.AddSqlBuilder(typeof(SqlConnection), new CustomSqlBuilder());\n```\n\n\u003chr\u003e\n\n## Extensibility\n#### `ITableNameResolver`\nImplement this interface if you want to customize the resolving of table names when building SQL queries.\n\n```cs\npublic class CustomTableNameResolver : ITableNameResolver\n{\n    public string ResolveTableName(Type type)\n    {\n        // Every table has prefix 'tbl'.\n        return $\"tbl{type.Name}\";\n    }\n}\n```\n\nUse the `SetTableNameResolver()` method to register the custom implementation:\n```cs\nSetTableNameResolver(new CustomTableNameResolver());\n```\n\n#### `IKeyPropertyResolver`\nImplement this interface if you want to customize the resolving of the key property of an entity. By default, Dommel will search for a property with the `[Key]` attribute, or a column with the name 'Id'.\n\nIf you, for example, have the naming convention of `{TypeName}Id` for key properties, you would implement the `IKeyPropertyResolver` like this:\n\n```cs\npublic class CustomKeyPropertyResolver : IKeyPropertyResolver\n{\n    public ColumnPropertyInfo[] ResolveKeyProperties(Type type)\n    {\n        return new [] { new ColumnPropertyInfo(type.GetProperties().Single(p =\u003e p.Name == $\"{type.Name}Id\"), isKey: true) };\n    }\n}\n```\n\nUse the `SetKeyPropertyResolver()` method to register the custom implementation:\n\n```cs\nDommelMapper.SetKeyPropertyResolver(new CustomKeyPropertyResolver());\n```\n\n#### `IForeignKeyPropertyResolver`\nImplement this interface if you want to customize the resolving of the foreign key property from one entity to another. By default Dommel will search for a property of `{TypeName}Id` or the column name specified using the `[ForeignKey]` attribute.\n\n\u003e This is a rather advanced interface. Providing your own implementation requires quite some knowledge of the way Dommel handles foreign key relationships. Consider subclassing `DefaultForeignKeyPropertyResolver` and override `ResolveForeignKeyProperty()`.\n\nUse the `SetForeignKeyPropertyResolver()` method to register the custom implementation:\n\n```cs\nDommelMapper.SetForeignKeyPropertyResolver(new CustomForeignKeyPropertyResolver());\n```\n\n#### `IColumnNameResolver`\nImplement this interface if you want to customize the resolving of column names for when building SQL queries. This is useful when your naming conventions for database columns are different than your POCO properties.\n\n```cs\npublic class CustomColumnNameResolver : IColumnNameResolver\n{\n    public string ResolveColumnName(PropertyInfo propertyInfo)\n    {\n        // Every column has prefix 'fld' and is uppercase.\n        return $\"fld{propertyInfo.Name.ToUpper()}\";\n    }\n}\n```\n\nUse the `SetColumnNameResolver()` method to register the custom implementation:\n\n```cs\nDommelMapper.SetColumnNameResolver(new CustomColumnNameResolver());\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenkmollema%2FDommel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhenkmollema%2FDommel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhenkmollema%2FDommel/lists"}