Dapper.SimpleCRUD
2.4.0-beta1
dotnet add package Dapper.SimpleCRUD --version 2.4.0-beta1
NuGet\Install-Package Dapper.SimpleCRUD -Version 2.4.0-beta1
<PackageReference Include="Dapper.SimpleCRUD" Version="2.4.0-beta1" />
<PackageVersion Include="Dapper.SimpleCRUD" Version="2.4.0-beta1" />
<PackageReference Include="Dapper.SimpleCRUD" />
paket add Dapper.SimpleCRUD --version 2.4.0-beta1
#r "nuget: Dapper.SimpleCRUD, 2.4.0-beta1"
#:package Dapper.SimpleCRUD@2.4.0-beta1
#addin nuget:?package=Dapper.SimpleCRUD&version=2.4.0-beta1&prerelease
#tool nuget:?package=Dapper.SimpleCRUD&version=2.4.0-beta1&prerelease
Dapper.SimpleCRUD - simple CRUD helpers for Dapper
Features
<img align="right" src="https://raw.githubusercontent.com/ericdc1/Dapper.SimpleCRUD/master/images/SimpleCRUD-200x200.png" alt="SimpleCRUD"> Dapper.SimpleCRUD is a single file you can drop in to your project that will extend your IDbConnection interface. (If you want dynamic support, you need an additional file.)
Who wants to write basic read/insert/update/delete statements?
The existing Dapper extensions did not fit my ideal pattern. I wanted simple CRUD operations with smart defaults without anything extra. I also wanted to have models with additional properties that did not directly map to the database. For example - a FullName property that combines FirstName and LastName in its getter - and not add FullName to the Insert and Update statements.
I wanted the primary key column to be Id in most cases but allow overriding with an attribute.
Finally, I wanted the table name to match the class name by default but allow overriding with an attribute.
This extension adds the following 8 helpers:
- Get(id) - gets one record based on the primary key
- GetList<Type>() - gets list of records all records from a table
- GetList<Type>(anonymous object for where clause) - gets list of all records matching the where options
- GetList<Type>(string for conditions, anonymous object with parameters) - gets list of all records matching the conditions
- GetListPaged<Type>(int pagenumber, int itemsperpage, string for conditions, string for order, anonymous object with parameters) - gets paged list of all records matching the conditions
- Insert(entity) - Inserts a record and returns the new primary key (assumes int primary key)
- Insert<Guid,T>(entity) - Inserts a record and returns the new guid primary key
- Update(entity) - Updates a record
- Delete<Type>(id) - Deletes a record based on primary key
- Delete(entity) - Deletes a record based on the typed entity
- DeleteList<Type>(anonymous object for where clause) - deletes all records matching the where options
- DeleteList<Type>(string for conditions, anonymous object with parameters) - deletes list of all records matching the conditions
- RecordCount<Type>(string for conditions,anonymous object with parameters) -gets count of all records matching the conditions
For projects targeting .NET 4.5 or later, the following 8 helpers exist for async operations:
- GetAsync(id) - gets one record based on the primary key
- GetListAsync<Type>() - gets list of records all records from a table
- GetListAsync<Type>(anonymous object for where clause) - gets list of all records matching the where options
- GetListAsync<Type>(string for conditions, anonymous object with parameters) - gets list of all records matching the conditions
- GetListPagedAsync<Type>(int pagenumber, int itemsperpage, string for conditions, string for order, anonymous object with parameters) - gets paged list of all records matching the conditions
- InsertAsync(entity) - Inserts a record and returns the new primary key (assumes int primary key)
- InsertAsync<Guid,T>(entity) - Inserts a record and returns the new guid primary key
- UpdateAsync(entity) - Updates a record
- DeleteAsync<Type>(id) - Deletes a record based on primary key
- DeleteAsync(entity) - Deletes a record based on the typed entity
- DeleteListAsync<Type>(anonymous object for where clause) - deletes all records matching the where options
- DeleteListAsync<Type>(string for conditions, anonymous object with parameters) - deletes list of all records matching the conditions
- RecordCountAsync<Type>(string for conditions, anonymous object with parameters) -gets count of all records matching the conditions
If you need something more complex use Dapper's Query or Execute methods!
Note: all extension methods assume the connection is already open, they will fail if the connection is closed.
Install via NuGet - https://nuget.org/packages/Dapper.SimpleCRUD
Check out the model generator T4 template to generate your POCOs. Documentation is at https://github.com/ericdc1/Dapper.SimpleCRUD/wiki/T4-Template
Get a single record mapped to a strongly typed object
public static T Get<T>(this IDbConnection connection, int id)
Example basic usage:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
var user = connection.Get<User>(1);
Results in executing this SQL
Select Id, Name, Age from [User] where Id = 1
More complex example:
[Table("Users")]
public class User
{
[Key]
public int UserId { get; set; }
[Column("strFirstName")]
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
var user = connection.Get<User>(1);
Results in executing this SQL
Select UserId, strFirstName as FirstName, LastName, Age from [Users] where UserId = @UserID
Notes:
The [Key] attribute can be used from the Dapper namespace or from System.ComponentModel.DataAnnotations
The [Table] attribute can be used from the Dapper namespace, System.ComponentModel.DataAnnotations.Schema, or System.Data.Linq.Mapping - By default the database table name will match the model name but it can be overridden with this.
The [Column] attribute can be used from the Dapper namespace, System.ComponentModel.DataAnnotations.Schema, or System.Data.Linq.Mapping - By default the column name will match the property name but it can be overridden with this. You can even use the model property names in the where clause anonymous object and SimpleCRUD will generate a proper where clause to match the database based on the column attribute
GUID (uniqueidentifier) primary keys are supported (autopopulates if no value is passed in)
Execute a query and map the results to a strongly typed List
public static IEnumerable<T> GetList<T>(this IDbConnection connection)
Example usage:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
var user = connection.GetList<User>();
Results in
Select * from [User]
Execute a query with where conditions and map the results to a strongly typed List
public static IEnumerable<T> GetList<T>(this IDbConnection connection, object whereConditions)
Example usage:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
var user = connection.GetList<User>(new { Age = 10 });
Results in
Select * from [User] where Age = @Age
Notes:
- To get all records use an empty anonymous object - new{}
- The where options are mapped as "where [name] = [value]"
- If you need > < like, etc simply use the manual where clause method or Dapper's Query method
- By default the select statement would include all properties in the class - The IgnoreSelect attributes remove items from the select statement
Execute a query with a where clause and map the results to a strongly typed List
public static IEnumerable<T> GetList<T>(this IDbConnection connection, string conditions, object parameters = null)
Example usage:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
var user = connection.GetList<User>("where age = 10 or Name like '%Smith%'");
or with parameters
var encodeForLike = term => term.Replace("[", "[[]").Replace("%", "[%]");
string likename = "%" + encodeForLike("Smith") + "%";
var user = connection.GetList<User>("where age = @Age or Name like @Name", new {Age = 10, Name = likename});
Results in
Select * from [User] where age = 10 or Name like '%Smith%'
Notes:
- This uses your raw SQL so be careful to not create SQL injection holes or use the Parameters option
- There is nothing stopping you from adding an order by clause using this method
Execute a query with a where clause and map the results to a strongly typed List with Paging
public static IEnumerable<T> GetListPaged<T>(this IDbConnection connection, int pageNumber, int rowsPerPage, string conditions, string orderby, object parameters = null)
Example usage:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
var user = connection.GetListPaged<User>(1,10,"where age = 10 or Name like '%Smith%'","Name desc");
Results in (SQL Server dialect)
SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY Name desc) AS PagedNumber, Id, Name, Age FROM [User] where age = 10 or Name like '%Smith%') AS u WHERE PagedNUMBER BETWEEN ((1 - 1) * 10 + 1) AND (1 * 10)
or with parameters
var user = connection.GetListPaged<User>(1,10,"where age = @Age","Name desc", new {Age = 10});
Results in (SQL Server dialect)
SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY Name desc) AS PagedNumber, Id, Name, Age FROM [User] where age = 10) AS u WHERE PagedNUMBER BETWEEN ((1 - 1) * 10 + 1) AND (1 * 10)
Notes:
- This uses your raw SQL so be careful to not create SQL injection holes or use the Parameters option
- It is recommended to use https://github.com/martijnboland/MvcPaging for the paging helper for your views
- @Html.Pager(10, 1, 100) - items per page, page number, total records
Insert a record
public static int Insert(this IDbConnection connection, object entityToInsert)
Example usage:
[Table("Users")]
public class User
{
[Key]
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
//Additional properties not in database
[Editable(false)]
public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } }
public List<User> Friends { get; set; }
[ReadOnly(true)]
public DateTime CreatedDate { get; set; }
}
var newId = connection.Insert(new User { FirstName = "User", LastName = "Person", Age = 10 });
Results in executing this SQL
Insert into [Users] (FirstName, LastName, Age) VALUES (@FirstName, @LastName, @Age)
Notes:
- Default table name would match the class name - The Table attribute overrides this
- Default primary key would be Id - The Key attribute overrides this
- By default the insert statement would include all properties in the class - The Editable(false), ReadOnly(true), and IgnoreInsert attributes remove items from the insert statement
- Properties decorated with ReadOnly(true) are only used for selects
- Complex types are not included in the insert statement - This keeps the List<User> out of the insert even without the Editable attribute. You can include complex types if you decorate them with Editable(true). This is useful for enumerators.
Insert a record with Guid key
public static int Insert<Guid,T>(this IDbConnection connection, object entityToInsert)
Example usage:
[Table("Users")]
public class User
{
[Key]
public Guid GuidKey { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
var newGuid = connection.Insert<Guid,User>(new User { FirstName = "User", LastName = "Person", Age = 10 });
Results in executing this SQL
Insert into [Users] (FirstName, LastName, Age) VALUES (@FirstName, @LastName, @Age)
Update a record
public static int Update(this IDbConnection connection, object entityToUpdate)
Example usage:
[Table("Users")]
public class User
{
[Key]
public int UserId { get; set; }
[Column("strFirstName")]
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
//Additional properties not in database
[Editable(false)]
public string FullName { get { return string.Format("{0} {1}", FirstName, LastName); } }
public List<User> Friends { get; set; }
}
connection.Update(entity);
Results in executing this SQL
Update [Users] Set (strFirstName=@FirstName, LastName=@LastName, Age=@Age) Where ID = @ID
Notes:
- By default the update statement would include all properties in the class - The Editable(false), ReadOnly(true), and IgnoreUpdate attributes remove items from the update statement
Delete a record
public static int Delete<T>(this IDbConnection connection, int Id)
Example usage:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
connection.Delete<User>(newid);
Or
public static int Delete<T>(this IDbConnection connection, T entityToDelete)
Example usage:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
connection.Delete(entity);
Results in executing this SQL
Delete From [User] Where ID = @ID
Delete multiple records with where conditions
public static int DeleteList<T>(this IDbConnection connection, object whereConditions, IDbTransaction transaction = null, int? commandTimeout = null)
Example usage:
connection.DeleteList<User>(new { Age = 10 });
Delete multiple records with where clause
public static int DeleteList<T>(this IDbConnection connection, string conditions, object parameters = null, IDbTransaction transaction = null, int? commandTimeout = null)
Example usage:
connection.DeleteList<User>("Where age > 20");
or with parameters
connection.DeleteList<User>("Where age > @Age", new {Age = 20});
Get count of records
public static int RecordCount<T>(this IDbConnection connection, string conditions = "", object parameters = null)
Example usage:
var count = connection.RecordCount<User>("Where age > 20");
or with parameters
var count = connection.RecordCount<User>("Where age > @Age", new {Age = 20});
Custom table and column name resolvers
You can also change the format of table and column names, first create a class implimenting the ITableNameResolver and/or IColumnNameResolver interfaces
public class CustomResolver : SimpleCRUD.ITableNameResolver, SimpleCRUD.IColumnNameResolver
{
public string ResolveTableName(Type type)
{
return string.Format("tbl_{0}", type.Name);
}
public string ResolveColumnName(PropertyInfo propertyInfo)
{
return string.Format("{0}_{1}", propertyInfo.DeclaringType.Name, propertyInfo.Name);
}
}
then apply the resolvers when intializing your application
var resolver = new CustomResolver();
SimpleCRUD.SetTableNameResolver(resolver);
SimpleCRUD.SetColumnNameResolver(resolver);
Database support
- There is an option to change database dialect. Default is Microsoft SQL Server but can be changed to PostgreSQL or MySQL. We dropped SQLite support with the .Net Core release.
SimpleCRUD.SetDialect(SimpleCRUD.Dialect.PostgreSQL);
SimpleCRUD.SetDialect(SimpleCRUD.Dialect.MySQL);
Attributes
The following attributes can be applied to properties in your model
[Table("YourTableName")] - By default the database table name will match the model name but it can be overridden with this.
[Column("YourColumnName"] - By default the column name will match the property name but it can be overridden with this. You can even use the model property names in the where clause anonymous object and SimpleCRUD will generate a proper where clause to match the database based on the column attribute
[Key] -By default the Id integer field is considered the primary key and is excluded from insert. The [Key] attribute lets you specify any Int or Guid as the primary key.
[Required] - By default the [Key] property is not inserted as it is expected to be an autoincremented by the database. You can mark a property as a [Key] and [Required] if you want to specify the value yourself during the insert.
[Editable(false)] - By default the select, insert, and update statements include all properties in the class - The Editable(false) and attribute excludes the property from being included. A good example for this is a FullName property that is derived from combining FirstName and Lastname in the model but the FullName field isn't actually in the database. Complex types are not included in the insert statement - This keeps the List out of the insert even without the Editable attribute.
[ReadOnly(true)] - Properties decorated with ReadOnly(true) are only used for selects and are excluded from inserts and updates. This would be useful for fields like CreatedDate where the database generates the date on insert and you never want to modify it.
[IgnoreSelect] - Excludes the property from selects
[IgnoreInsert] - Excludes the property from inserts
[IgnoreUpdate] - Excludes the property from updates
[NotMapped] - Excludes the property from all operations
Do you have a comprehensive list of examples?
Dapper.SimpleCRUD has a basic test suite in the test project
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Dapper (>= 2.1.79)
- Microsoft.CSharp (>= 4.7.0)
NuGet packages (45)
Showing the top 5 NuGet packages that depend on Dapper.SimpleCRUD:
| Package | Downloads |
|---|---|
|
EachShow.DataAccess.Core
Package Description |
|
|
Edakik.Shared.Library
Package Description |
|
|
YuckQi.Data.Sql.Dapper
An implementation of YuckQi.Data for SQL databases using Dapper and SimpleCRUD. |
|
|
TianFeng.FrameworkCore
天枫 .net core 组件,支持.net6 |
|
|
Cigel.DotNetCore
Package Description |
GitHub repositories (2)
Showing the top 2 popular GitHub repositories that depend on Dapper.SimpleCRUD:
| Repository | Stars |
|---|---|
|
yilezhu/Czar.Cms
.NET Core实战项目之CMS系列教程的源码,精简而又功能丰富的权限设计,内容管理设计让你轻松搭建一个ASP.NET Core2.2的网站系统.此项目准备用EFCore进行重构,敬请期待
|
|
|
MoonStorm/FastCrud
fast .NET ORM for strongly typed people
|
| Version | Downloads | Last Updated |
|---|---|---|
| 2.4.0-beta1 | 35 | 8/21/2026 |
| 2.3.0 | 3,195,316 | 3/15/2021 |
| 2.2.0.1 | 1,501,987 | 12/18/2019 |
| 2.2.0 | 269,051 | 10/2/2019 |
| 2.1.0 | 404,285 | 2/22/2019 |
| 2.0.1 | 215,847 | 10/2/2018 |
| 2.0.0 | 62,227 | 7/12/2018 |
| 2.0.0-beta | 3,677 | 7/9/2018 |
| 1.13.0 | 372,337 | 9/19/2016 |
| 1.12.0 | 20,939 | 8/1/2016 |
| 1.11.1 | 21,081 | 6/16/2016 |
| 1.11.0 | 11,515 | 6/15/2016 |
| 1.10.0 | 38,680 | 12/3/2015 |
| 1.9.3 | 11,709 | 12/1/2015 |
| 1.9.2 | 24,275 | 10/27/2015 |
| 1.9.1 | 15,338 | 8/29/2015 |
| 1.9.0 | 12,453 | 7/27/2015 |
| 1.9.0-beta | 3,651 | 7/22/2015 |
| 1.8.7 | 56,632 | 5/14/2015 |
| 1.8.6 | 16,285 | 4/23/2015 |
Full documentation can be found at https://github.com/ericdc1/Dapper.SimpleCRUD/
* version 1.3.0: Support for multiple schemas, non int primary keys. Fixed issue with editable attribute annotations. Made enums be considered "editable" so you can have integers in the database and represent them as enums in the code and have SimpleCRUD map them without extra pain.
* version 1.4.0: Switched to using Nullable.GetUnderlyingType(type) so we don't need to explicitly check for all nullable types. This also has the side effect of fixing checks for nullable enums without the editable attribute.
* version 1.4.1: Added support for short and long primary key types on insert method
* version 1.5.0 Target .Net 4.5, support for PostgreSQL, SQL Server now uses scope_identity on insert rather than @@identity. Add support for GUID primary keys
* version 1.6.0 Target .Net 4.0 and 4.5 and add async support / remove SQLCE support Special thanks to https://github.com/Prnda1976 for help with the pull request backlog
* version 1.7.0 Added column attribute and made gets specify column names rather than select * . Changed GUID to autogenerate when the property value is empty. Ability to change database dialect from SQL Server to PostgreSQL.
* version 1.8.0 Added support and tests for SQLite. Added additional GetList method that accepts a raw SQL where clause for more advanced queries.
* version 1.8.2 Added logo, updated package description
* version 1.8.3 Fix for async get method, added additional tests around async methods
* version 1.8.4 Fix for custom column name on primary key in get and delete methods
* version 1.8.5 Added support for ReadOnly attribute on properties which allows selecting it from the database but ignores it on inserts and updates
* version 1.8.6 Allow a column named Id column to not be considered a key when another [Key] is specified
* version 1.8.7 Fix for GUID primary key named Id
* version 1.9.0 Added GetListPaged, DeleteList, and RecordCount methods and support for specified value in primary key
* version 1.9.1 MySQL Support
* version 1.9.2 Fix for async insert with specified value in primary key
* version 1.9.3 Fix for issue with GetPagedList with custom column name for primary key - Thanks haleaurelian. Added DeleteList with anonymous object
* version 1.10.0 Added IgnoreUpdate, IgnoreInsert, and IgnoreSelect attributes
* version 1.11.0 Added resolvers PR, typed attributes, merged recordcount where conditions PR, performance improvements PR
* version 1.11.1 Bug fix for resolvers to allow attributes from different namespaces (SimpleCRUD and Data Annotations)
* version 1.12.0 Added notmapped attribute to match DataAnnotations (thanks Mattykins). Allow insert with string primary key (thanks xalikoutis)
* version 1.13.0 Accept parameters on getlist, getlistpaged, deletelist, recordcount, and matching async methods
* version 2.0.0 Bug fixes, .Net Core support, remove Sqlite support
* version 2.0.1 Re-add SQLite, allow string primary keys
* version 2.1.0 Speed improvements (thanks jonathanlarouche)
* version 2.2.0 Dapper 2.x support
* version 2.3.0 Update DB2 support (mvaz77), Interface support (jonathanlarouche)
* version 2.4.0 Updated NuGet packages (Dapper 2.1.79). Added opt-in column inclusion via [Key]/[Column] attributes (davethieben).