├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── cla.yml │ └── main.yml ├── .gitignore ├── Build.csproj ├── Dapper.EntityFramework.StrongName └── Dapper.EntityFramework.StrongName.csproj ├── Dapper.EntityFramework ├── Dapper.EntityFramework.csproj ├── DbGeographyHandler.cs ├── DbGeometryHandler.cs ├── Handlers.cs ├── PublicAPI.Shipped.txt └── PublicAPI.Unshipped.txt ├── Dapper.ProviderTools ├── BulkCopy.cs ├── Dapper.ProviderTools.csproj ├── DbConnectionExtensions.cs ├── DbExceptionExtensions.cs ├── Internal │ └── DynamicBulkCopy.cs ├── PublicAPI.Shipped.txt └── PublicAPI.Unshipped.txt ├── Dapper.Rainbow ├── Dapper.Rainbow.csproj ├── Database.Async.cs ├── Database.cs ├── IgnorePropertyAttribute.cs ├── Snapshotter.cs ├── SqlCompactDatabase.cs └── readme.md ├── Dapper.SqlBuilder ├── Dapper.SqlBuilder.csproj ├── PublicAPI.Shipped.txt ├── PublicAPI.Unshipped.txt ├── Readme.md └── SqlBuilder.cs ├── Dapper.StrongName └── Dapper.StrongName.csproj ├── Dapper.png ├── Dapper.sln ├── Dapper.sln.DotSettings ├── Dapper.snk ├── Dapper ├── CommandDefinition.cs ├── CommandFlags.cs ├── CompiledRegex.cs ├── CustomPropertyTypeMap.cs ├── Dapper.csproj ├── DataTableHandler.cs ├── DbString.cs ├── DefaultTypeMap.cs ├── DynamicParameters.CachedOutputSetters.cs ├── DynamicParameters.ParamInfo.cs ├── DynamicParameters.cs ├── ExplicitConstructorAttribute.cs ├── Extensions.cs ├── FeatureSupport.cs ├── Global.cs ├── NRT.cs ├── Properties │ └── AssemblyInfo.cs ├── PublicAPI.Shipped.txt ├── PublicAPI.Unshipped.txt ├── PublicAPI │ ├── net461 │ │ ├── PublicAPI.Shipped.txt │ │ └── PublicAPI.Unshipped.txt │ ├── net8.0 │ │ ├── PublicAPI.Shipped.txt │ │ └── PublicAPI.Unshipped.txt │ └── netstandard2.0 │ │ ├── PublicAPI.Shipped.txt │ │ └── PublicAPI.Unshipped.txt ├── SimpleMemberMap.cs ├── SqlDataRecordHandler.cs ├── SqlDataRecordListTVPParameter.cs ├── SqlMapper.Async.cs ├── SqlMapper.CacheInfo.cs ├── SqlMapper.DapperRow.Descriptor.cs ├── SqlMapper.DapperRow.cs ├── SqlMapper.DapperRowMetaObject.cs ├── SqlMapper.DapperTable.cs ├── SqlMapper.DeserializerState.cs ├── SqlMapper.DontMap.cs ├── SqlMapper.GridReader.Async.cs ├── SqlMapper.GridReader.cs ├── SqlMapper.ICustomQueryParameter.cs ├── SqlMapper.IDataReader.cs ├── SqlMapper.IDynamicParameters.cs ├── SqlMapper.IMemberMap.cs ├── SqlMapper.IParameterCallbacks.cs ├── SqlMapper.IParameterLookup.cs ├── SqlMapper.ITypeHandler.cs ├── SqlMapper.ITypeMap.cs ├── SqlMapper.Identity.cs ├── SqlMapper.Link.cs ├── SqlMapper.LiteralToken.cs ├── SqlMapper.Settings.cs ├── SqlMapper.TypeDeserializerCache.cs ├── SqlMapper.TypeHandler.cs ├── SqlMapper.TypeHandlerCache.cs ├── SqlMapper.cs ├── TableValuedParameter.cs ├── TypeExtensions.cs ├── UdtTypeHandler.cs ├── WrappedDataReader.cs ├── WrappedReader.cs └── XmlHandlers.cs ├── Directory.Build.props ├── Directory.Build.targets ├── Directory.Packages.props ├── License.txt ├── NonCLA.md ├── Readme.md ├── appveyor.yml ├── benchmarks ├── Dapper.Tests.Performance │ ├── Benchmarks.Belgrade.cs │ ├── Benchmarks.Dapper.cs │ ├── Benchmarks.Dashing.cs │ ├── Benchmarks.EntityFramework.cs │ ├── Benchmarks.EntityFrameworkCore.cs │ ├── Benchmarks.HandCoded.cs │ ├── Benchmarks.Linq2DB.cs │ ├── Benchmarks.Linq2Sql.cs │ ├── Benchmarks.Massive.cs │ ├── Benchmarks.Mighty.cs │ ├── Benchmarks.NHibernate.cs │ ├── Benchmarks.Norm.cs │ ├── Benchmarks.PetaPoco.cs │ ├── Benchmarks.RepoDB.cs │ ├── Benchmarks.ServiceStack.cs │ ├── Benchmarks.SqlMarshal.cs │ ├── Benchmarks.Susanoo.cs │ ├── Benchmarks.XPO.cs │ ├── Benchmarks.cs │ ├── Config.cs │ ├── Dapper.Tests.Performance.csproj │ ├── DapperCacheImpact.cs │ ├── Dashing │ │ ├── DashingConfiguration.cs │ │ └── Post.cs │ ├── EntityFramework │ │ └── EFContext.cs │ ├── EntityFrameworkCore │ │ └── EFCoreContext.cs │ ├── Helpers │ │ ├── ORMColum.cs │ │ └── ReturnColum.cs │ ├── LegacyTests.cs │ ├── Linq2DB │ │ ├── ConnectionStringSettings.cs │ │ ├── Linq2DBContext.cs │ │ └── Linq2DbSettings.cs │ ├── Linq2Sql │ │ ├── DataClasses.dbml │ │ ├── DataClasses.dbml.layout │ │ └── DataClasses.designer.cs │ ├── Massive │ │ └── Massive.cs │ ├── NHibernate │ │ ├── NHibernateHelper.cs │ │ ├── Post.hbm.xml │ │ └── hibernate.cfg.xml │ ├── PetaPoco │ │ └── PetaPoco.cs │ ├── Post.cs │ ├── Program.cs │ ├── SqlDataReaderHelper.cs │ ├── XPO │ │ └── Post.cs │ └── app.config └── Directory.Build.props ├── build.cmd ├── build.ps1 ├── docs ├── _config.yml ├── dapper-sponsor.png ├── dapperplus.md ├── dapperplus.png ├── docs.csproj ├── index.md └── readme.md ├── global.json ├── nuget.config ├── signatures └── version1 │ └── cla.json ├── tests ├── Dapper.Tests │ ├── App.config │ ├── AsyncTests.cs │ ├── ConstructorTests.cs │ ├── Dapper.Tests.csproj │ ├── DataReaderTests.cs │ ├── DateTimeOnlyTests.cs │ ├── DecimalTests.cs │ ├── EnumTests.cs │ ├── Helpers │ │ ├── Attributes.cs │ │ ├── Common.cs │ │ ├── IsExternalInit.cs │ │ ├── SqlServerTypesLoader.cs │ │ ├── TransactedConnection.cs │ │ └── XunitSkippable.cs │ ├── LiteralTests.cs │ ├── MiscTests.cs │ ├── MultiMapTests.cs │ ├── NullTests.cs │ ├── ParameterTests.cs │ ├── ProcedureTests.cs │ ├── ProviderTests.cs │ ├── Providers │ │ ├── DuckDBTests.cs │ │ ├── EntityFrameworkTests.cs │ │ ├── FirebirdTests.cs │ │ ├── Linq2SqlTests.cs │ │ ├── MySQLTests.cs │ │ ├── OLDEBTests.cs │ │ ├── PostgresqlTests.cs │ │ ├── SnowflakeTests.cs │ │ └── SqliteTests.cs │ ├── QueryMultipleTests.cs │ ├── SharedTypes │ │ ├── Address.cs │ │ ├── Bar1.cs │ │ ├── Category.cs │ │ ├── Comment.cs │ │ ├── Dog.cs │ │ ├── Enums.cs │ │ ├── Foo1.cs │ │ ├── HazNameId.cs │ │ ├── Index.cs │ │ ├── Person.cs │ │ ├── Post.cs │ │ ├── Product.cs │ │ ├── ReviewBoard.cs │ │ ├── ShortEnum.cs │ │ ├── SomeType.cs │ │ └── User.cs │ ├── SingleRowTests.cs │ ├── SqlBuilderTests.cs │ ├── TestBase.cs │ ├── TransactionTests.cs │ ├── TupleTests.cs │ ├── TypeHandlerTests.cs │ ├── WrappedReaderTests.cs │ ├── XmlTests.cs │ └── xunit.runner.json ├── Directory.Build.props ├── Directory.Build.targets └── docker-compose.yml └── version.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome:http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Don't use tabs for indentation. 7 | [*] 8 | indent_style = space 9 | # (Please don't specify an indent_size here; that has too many unintended consequences.) 10 | 11 | # Code files 12 | [*.{cs,csx,vb,vbx}] 13 | indent_size = 4 14 | insert_final_newline = true 15 | charset = utf-8-bom 16 | 17 | # Xml project files 18 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] 19 | indent_size = 2 20 | 21 | # Xml config files 22 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] 23 | indent_size = 2 24 | 25 | # JSON files 26 | [*.json] 27 | indent_size = 2 28 | 29 | # Dotnet code style settings: 30 | [*.{cs,vb}] 31 | # Sort using and Import directives with System.* appearing first 32 | dotnet_sort_system_directives_first = true 33 | # Avoid "this." and "Me." if not necessary 34 | dotnet_style_qualification_for_field = false:suggestion 35 | dotnet_style_qualification_for_property = false:suggestion 36 | dotnet_style_qualification_for_method = false:suggestion 37 | dotnet_style_qualification_for_event = false:suggestion 38 | 39 | # Use language keywords instead of framework type names for type references 40 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 41 | dotnet_style_predefined_type_for_member_access = true:suggestion 42 | 43 | # Suggest more modern language features when available 44 | dotnet_style_object_initializer = true:suggestion 45 | dotnet_style_collection_initializer = true:suggestion 46 | dotnet_style_coalesce_expression = true:suggestion 47 | dotnet_style_null_propagation = true:suggestion 48 | dotnet_style_explicit_tuple_names = true:suggestion 49 | 50 | # CSharp code style settings: 51 | [*.cs] 52 | # Prefer "var" everywhere 53 | #csharp_style_var_for_built_in_types = true:suggestion 54 | #csharp_style_var_when_type_is_apparent = false:suggestion 55 | #csharp_style_var_elsewhere = true:suggestion 56 | 57 | # Prefer method-like constructs to have a expression-body 58 | csharp_style_expression_bodied_methods = true:none 59 | csharp_style_expression_bodied_constructors = true:none 60 | csharp_style_expression_bodied_operators = true:none 61 | 62 | # Prefer property-like constructs to have an expression-body 63 | csharp_style_expression_bodied_properties = true:none 64 | csharp_style_expression_bodied_indexers = true:none 65 | csharp_style_expression_bodied_accessors = true:none 66 | 67 | # Suggest more modern language features when available 68 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 69 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 70 | csharp_style_inlined_variable_declaration = true:suggestion 71 | csharp_style_throw_expression = true:suggestion 72 | csharp_style_conditional_delegate_call = true:suggestion 73 | 74 | # Newline settings 75 | csharp_new_line_before_open_brace = all 76 | csharp_new_line_before_else = true 77 | csharp_new_line_before_catch = true 78 | csharp_new_line_before_finally = true 79 | csharp_new_line_before_members_in_object_initializers = true 80 | csharp_new_line_before_members_in_anonymous_types = true -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.doc diff=astextplain 4 | *.DOC diff=astextplain 5 | *.docx diff=astextplain 6 | *.DOCX diff=astextplain 7 | *.dot diff=astextplain 8 | *.DOT diff=astextplain 9 | *.pdf diff=astextplain 10 | *.PDF diff=astextplain 11 | *.rtf diff=astextplain 12 | *.RTF diff=astextplain 13 | 14 | *.jpg binary 15 | *.png binary 16 | *.gif binary 17 | 18 | *.cs -text diff=csharp 19 | *.vb -text 20 | *.c -text 21 | *.cpp -text 22 | *.cxx -text 23 | *.h -text 24 | *.hxx -text 25 | *.py -text 26 | *.rb -text 27 | *.java -text 28 | *.html -text 29 | *.htm -text 30 | *.css -text 31 | *.scss -text 32 | *.sass -text 33 | *.less -text 34 | *.js -text 35 | *.lisp -text 36 | *.clj -text 37 | *.sql -text 38 | *.php -text 39 | *.lua -text 40 | *.m -text 41 | *.asm -text 42 | *.erl -text 43 | *.fs -text 44 | *.fsx -text 45 | *.hs -text 46 | 47 | *.csproj -text merge=union 48 | *.vbproj -text merge=union 49 | *.fsproj -text merge=union 50 | *.dbproj -text merge=union 51 | *.sln -text merge=union 52 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [mgravell, dapperlib] 4 | custom: ["https://www.buymeacoffee.com/marcgravell"] 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug, needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Check your library version, and try updating** 11 | To help, we're going to need to know your library version. If it isn't the latest: *go do that* - it might 12 | fix the problem, and even if it doesn't: you're going to need to update if we find a problem and fix it, 13 | so you might as well get ready for that now. 14 | 15 | **Describe the bug** 16 | A clear and concise description of what the bug is. 17 | 18 | **To Reproduce** 19 | Steps to reproduce the behavior: 20 | 1. Go to '...' 21 | 2. Click on '....' 22 | 3. Scroll down to '....' 23 | 4. See error 24 | 25 | **Expected and actual behavior** 26 | A clear and concise description of what you expected to happen, and what actually happens. 27 | 28 | **Additional context** 29 | Add any other context about the problem here: 30 | - what DB backend (and version) are you using, if relevant? 31 | - what ADO.NET provider (and version) are you using, if relevant? 32 | - what OS and .NET runtime (and version) are you using, if relevant? 33 | -------------------------------------------------------------------------------- /.github/workflows/cla.yml: -------------------------------------------------------------------------------- 1 | name: "CLA Assistant" 2 | on: 3 | issue_comment: 4 | types: [created] 5 | pull_request_target: 6 | types: [opened,closed,synchronize] 7 | 8 | # explicitly configure permissions, in case your GITHUB_TOKEN workflow permissions are set to read-only in repository settings 9 | permissions: 10 | actions: write 11 | contents: write 12 | pull-requests: write 13 | statuses: write 14 | 15 | jobs: 16 | CLAAssistant: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: "CLA Assistant" 20 | if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' 21 | uses: contributor-assistant/github-action@v2.3.0 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | # the below token should have repo scope and must be manually added by you in the repository's secret 25 | # This token is required only if you have configured to store the signatures in a remote repository/organization 26 | PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} 27 | with: 28 | path-to-signatures: 'signatures/version1/cla.json' 29 | path-to-document: 'https://raw.githubusercontent.com/DapperLib/Dapper/main/NonCLA.md' # e.g. a CLA or a DCO document 30 | # branch should not be protected 31 | branch: 'main' 32 | # allowlist: user1,bot* 33 | 34 | # the followings are the optional inputs - If the optional inputs are not given, then default values will be taken 35 | #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) 36 | #remote-repository-name: enter the remote repository name where the signatures should be stored (Default is storing the signatures in the same repository) 37 | #create-file-commit-message: 'For example: Creating file for storing CLA Signatures' 38 | #signed-commit-message: 'For example: $contributorName has signed the CLA in $owner/$repo#$pullRequestNo' 39 | #custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign' 40 | #custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA' 41 | #custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.' 42 | #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) 43 | #use-dco-flag: true - If you are using DCO instead of CLA 44 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main Build 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | paths: 9 | - '*' 10 | - '!/docs/*' # Don't run workflow when files are only in the /docs directory 11 | 12 | jobs: 13 | vm-job: 14 | name: Ubuntu 15 | runs-on: ubuntu-latest 16 | services: 17 | postgres: 18 | image: postgres 19 | ports: 20 | - 5432/tcp 21 | env: 22 | POSTGRES_USER: postgres 23 | POSTGRES_PASSWORD: postgres 24 | POSTGRES_DB: test 25 | options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 26 | sqlserver: 27 | image: mcr.microsoft.com/mssql/server:2019-latest 28 | ports: 29 | - 1433/tcp 30 | env: 31 | ACCEPT_EULA: Y 32 | SA_PASSWORD: "Password." 33 | mysql: 34 | image: mysql 35 | ports: 36 | - 3306/tcp 37 | env: 38 | MYSQL_ROOT_PASSWORD: root 39 | MYSQL_DATABASE: test 40 | steps: 41 | - name: Checkout code 42 | uses: actions/checkout@v1 43 | - name: Setup dotnet 44 | uses: actions/setup-dotnet@v4 45 | with: 46 | dotnet-version: '9.0.x' 47 | - name: .NET Build 48 | run: dotnet build Build.csproj -c Release /p:CI=true 49 | - name: Dapper Tests 50 | run: dotnet test tests/Dapper.Tests/Dapper.Tests.csproj -c Release --logger GitHubActions -p:CI=true -p:TestTfmsInParallel=false 51 | env: 52 | MySqlConnectionString: Server=localhost;Port=${{ job.services.mysql.ports[3306] }};Uid=root;Pwd=root;Database=test;Allow User Variables=true 53 | OLEDBConnectionString: Provider=SQLOLEDB;Server=tcp:localhost,${{ job.services.sqlserver.ports[1433] }};Database=tempdb;User Id=sa;Password=Password.; 54 | PostgesConnectionString: Server=localhost;Port=${{ job.services.postgres.ports[5432] }};Database=test;User Id=postgres;Password=postgres; 55 | SqlServerConnectionString: Server=tcp:localhost,${{ job.services.sqlserver.ports[1433] }};Database=tempdb;User Id=sa;Password=Password.; 56 | - name: .NET Lib Pack 57 | run: dotnet pack Build.csproj --no-build -c Release /p:PackageOutputPath=%CD%\.nupkgs /p:CI=true 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /*.suo 2 | .vs/ 3 | .vscode/ 4 | bin/ 5 | obj/ 6 | /*.user 7 | _Resharper* 8 | .hgtags 9 | NuGet.exe 10 | *.user 11 | *.nupkg 12 | .nupkgs/ 13 | .docstats 14 | *.ide/ 15 | *.lock.json 16 | *.coverage 17 | Test.DB.* 18 | TestResults/ 19 | Dapper.Tests/*.sdf 20 | Dapper.Tests/SqlServerTypes/ 21 | .dotnet/* 22 | BenchmarkDotNet.Artifacts/ 23 | .idea/ 24 | .DS_Store -------------------------------------------------------------------------------- /Build.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Dapper.EntityFramework.StrongName/Dapper.EntityFramework.StrongName.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Dapper.EntityFramework.StrongName 4 | Dapper: Entity Framework type handlers (with a strong name) 5 | Extension handlers for entity framework 6 | Marc Gravell;Nick Craver 7 | net461 8 | ../Dapper.snk 9 | true 10 | true 11 | Dapper.EntityFramework.StrongName 12 | orm;sql;micro-orm 13 | enable 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Dapper.EntityFramework/Dapper.EntityFramework.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Dapper.EntityFramework 4 | Extension handlers for entity framework 5 | Dapper entity framework type handlers 6 | 1.50.2 7 | Marc Gravell;Nick Craver 8 | net461 9 | orm;sql;micro-orm 10 | enable 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers 20 | 21 | 22 | -------------------------------------------------------------------------------- /Dapper.EntityFramework/DbGeographyHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SqlServer.Types; 2 | using System; 3 | using System.Data; 4 | using System.Data.Entity.Spatial; 5 | using System.Data.SqlClient; 6 | using System.Data.SqlTypes; 7 | 8 | namespace Dapper.EntityFramework 9 | { 10 | /// 11 | /// Type-handler for the DbGeography spatial type. 12 | /// 13 | public class DbGeographyHandler : SqlMapper.TypeHandler 14 | { 15 | /// 16 | /// Create a new handler instance. 17 | /// 18 | protected DbGeographyHandler() { /* create new */ } 19 | 20 | /// 21 | /// Default handler instance 22 | /// 23 | public static readonly DbGeographyHandler Default = new DbGeographyHandler(); 24 | 25 | /// 26 | /// Assign the value of a parameter before a command executes. 27 | /// 28 | /// The parameter to configure. 29 | /// Parameter value. 30 | public override void SetValue(IDbDataParameter parameter, DbGeography? value) 31 | { 32 | object? parsed = null; 33 | if (value is not null) 34 | { 35 | parsed = SqlGeography.STGeomFromWKB(new SqlBytes(value.AsBinary()), value.CoordinateSystemId); 36 | } 37 | parameter.Value = parsed ?? DBNull.Value; 38 | if (parameter is SqlParameter sqlParameter) 39 | { 40 | sqlParameter.UdtTypeName = "geography"; 41 | } 42 | } 43 | 44 | /// 45 | /// Parse a database value back to a typed value. 46 | /// 47 | /// The value from the database. 48 | /// The typed value. 49 | public override DbGeography? Parse(object? value) 50 | { 51 | if (value is null || value is DBNull) return null; 52 | if (value is SqlGeography geo) 53 | { 54 | return DbGeography.FromBinary(geo.STAsBinary().Value, geo.STSrid.Value); 55 | } 56 | return DbGeography.FromText(value.ToString()); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Dapper.EntityFramework/DbGeometryHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.SqlServer.Types; 2 | using System; 3 | using System.Data; 4 | using System.Data.Entity.Spatial; 5 | using System.Data.SqlClient; 6 | using System.Data.SqlTypes; 7 | 8 | namespace Dapper.EntityFramework 9 | { 10 | /// 11 | /// Type-handler for the DbGeometry spatial type. 12 | /// 13 | public class DbGeometryHandler : SqlMapper.TypeHandler 14 | { 15 | /// 16 | /// Create a new handler instance. 17 | /// 18 | protected DbGeometryHandler() { /* create new */ } 19 | 20 | /// 21 | /// Default handler instance. 22 | /// 23 | public static readonly DbGeometryHandler Default = new DbGeometryHandler(); 24 | 25 | /// 26 | /// Assign the value of a parameter before a command executes. 27 | /// 28 | /// The parameter to configure. 29 | /// Parameter value. 30 | public override void SetValue(IDbDataParameter parameter, DbGeometry? value) 31 | { 32 | object? parsed = null; 33 | if (value is not null) 34 | { 35 | parsed = SqlGeometry.STGeomFromWKB(new SqlBytes(value.AsBinary()), value.CoordinateSystemId); 36 | } 37 | parameter.Value = parsed ?? DBNull.Value; 38 | if (parameter is SqlParameter sqlP) 39 | { 40 | sqlP.UdtTypeName = "geometry"; 41 | } 42 | } 43 | 44 | /// 45 | /// Parse a database value back to a typed value. 46 | /// 47 | /// The value from the database. 48 | /// The typed value. 49 | public override DbGeometry? Parse(object? value) 50 | { 51 | if (value is null || value is DBNull) return null; 52 | if (value is SqlGeometry geo) 53 | { 54 | return DbGeometry.FromBinary(geo.STAsBinary().Value, geo.STSrid.Value); 55 | } 56 | return DbGeometry.FromText(value.ToString()); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Dapper.EntityFramework/Handlers.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.EntityFramework 2 | { 3 | /// 4 | /// Acts on behalf of all type-handlers in this package 5 | /// 6 | public static class Handlers 7 | { 8 | /// 9 | /// Register all type-handlers in this package 10 | /// 11 | public static void Register() 12 | { 13 | SqlMapper.AddTypeHandler(DbGeographyHandler.Default); 14 | SqlMapper.AddTypeHandler(DbGeometryHandler.Default); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Dapper.EntityFramework/PublicAPI.Shipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | Dapper.EntityFramework.DbGeographyHandler 3 | Dapper.EntityFramework.DbGeographyHandler.DbGeographyHandler() -> void 4 | Dapper.EntityFramework.DbGeometryHandler 5 | Dapper.EntityFramework.DbGeometryHandler.DbGeometryHandler() -> void 6 | Dapper.EntityFramework.Handlers 7 | override Dapper.EntityFramework.DbGeographyHandler.Parse(object? value) -> System.Data.Entity.Spatial.DbGeography? 8 | override Dapper.EntityFramework.DbGeographyHandler.SetValue(System.Data.IDbDataParameter! parameter, System.Data.Entity.Spatial.DbGeography? value) -> void 9 | override Dapper.EntityFramework.DbGeometryHandler.Parse(object? value) -> System.Data.Entity.Spatial.DbGeometry? 10 | override Dapper.EntityFramework.DbGeometryHandler.SetValue(System.Data.IDbDataParameter! parameter, System.Data.Entity.Spatial.DbGeometry? value) -> void 11 | static Dapper.EntityFramework.Handlers.Register() -> void 12 | static readonly Dapper.EntityFramework.DbGeographyHandler.Default -> Dapper.EntityFramework.DbGeographyHandler! 13 | static readonly Dapper.EntityFramework.DbGeometryHandler.Default -> Dapper.EntityFramework.DbGeometryHandler! -------------------------------------------------------------------------------- /Dapper.EntityFramework/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable -------------------------------------------------------------------------------- /Dapper.ProviderTools/Dapper.ProviderTools.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Dapper.ProviderTools 4 | orm;sql;micro-orm 5 | Dapper Provider Tools 6 | Provider-agnostic ADO.NET helper utilities 7 | Marc Gravell 8 | net461;netstandard2.0;net8.0 9 | true 10 | enable 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Dapper.ProviderTools/DbExceptionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Data.Common; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | 7 | namespace Dapper.ProviderTools 8 | { 9 | /// 10 | /// Helper utilities for working with database exceptions 11 | /// 12 | public static class DbExceptionExtensions 13 | { 14 | /// 15 | /// Indicates whether the provided exception has an integer Number property with the supplied value 16 | /// 17 | public static bool IsNumber(this DbException exception, int number) 18 | => exception is not null && ByTypeHelpers.Get(exception.GetType()).IsNumber(exception, number); 19 | 20 | 21 | private sealed class ByTypeHelpers 22 | { 23 | private static readonly ConcurrentDictionary s_byType 24 | = new ConcurrentDictionary(); 25 | private readonly Func? _getNumber; 26 | 27 | public bool IsNumber(DbException exception, int number) 28 | => _getNumber is not null && _getNumber(exception) == number; 29 | 30 | public static ByTypeHelpers Get(Type type) 31 | { 32 | if (!s_byType.TryGetValue(type, out var value)) 33 | { 34 | s_byType[type] = value = new ByTypeHelpers(type); 35 | } 36 | return value; 37 | } 38 | 39 | private ByTypeHelpers(Type type) 40 | { 41 | _getNumber = TryGetInstanceProperty("Number", type); 42 | } 43 | 44 | private static Func? TryGetInstanceProperty(string name, Type type) 45 | { 46 | try 47 | { 48 | var prop = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance); 49 | if (prop is null || !prop.CanRead) return null; 50 | if (prop.PropertyType != typeof(T)) return null; 51 | 52 | var p = Expression.Parameter(typeof(DbException), "exception"); 53 | var body = Expression.Property(Expression.Convert(p, type), prop); 54 | var lambda = Expression.Lambda>(body, p); 55 | return lambda.Compile(); 56 | } 57 | catch 58 | { 59 | return null; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Dapper.ProviderTools/Internal/DynamicBulkCopy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Data.Common; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | #nullable enable 7 | namespace Dapper.ProviderTools.Internal 8 | { 9 | internal sealed class DynamicBulkCopy : BulkCopy 10 | { 11 | internal static BulkCopy? Create(object? wrapped) 12 | => wrapped is null ? null : new DynamicBulkCopy(wrapped); 13 | 14 | private DynamicBulkCopy(object wrapped) 15 | => _wrapped = wrapped; 16 | 17 | private readonly dynamic _wrapped; 18 | 19 | public override string DestinationTableName 20 | { 21 | get => _wrapped.DestinationTableName; 22 | set => _wrapped.DestinationTableName = value; 23 | } 24 | 25 | public override object Wrapped => _wrapped; 26 | 27 | public override void AddColumnMapping(string sourceColumn, string destinationColumn) 28 | => _wrapped.ColumnMappings.Add(sourceColumn, destinationColumn); 29 | 30 | public override void AddColumnMapping(int sourceColumn, int destinationColumn) 31 | => _wrapped.ColumnMappings.Add(sourceColumn, destinationColumn); 32 | 33 | public override void WriteToServer(DataTable source) 34 | => _wrapped.WriteToServer(source); 35 | public override void WriteToServer(DataRow[] source) 36 | => _wrapped.WriteToServer(source); 37 | 38 | public override void WriteToServer(IDataReader source) 39 | => _wrapped.WriteToServer(source); 40 | 41 | public override Task WriteToServerAsync(DbDataReader source, CancellationToken cancellationToken) 42 | => _wrapped.WriteToServer(source, cancellationToken); 43 | 44 | public override Task WriteToServerAsync(DataTable source, CancellationToken cancellationToken) 45 | => _wrapped.WriteToServer(source, cancellationToken); 46 | public override Task WriteToServerAsync(DataRow[] source, CancellationToken cancellationToken) 47 | => _wrapped.WriteToServer(source, cancellationToken); 48 | 49 | protected override void Dispose(bool disposing) 50 | { 51 | if (disposing) 52 | { 53 | if (_wrapped is IDisposable d) 54 | { 55 | try { d.Dispose(); } catch { } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Dapper.ProviderTools/PublicAPI.Shipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | abstract Dapper.ProviderTools.BulkCopy.AddColumnMapping(int sourceColumn, int destinationColumn) -> void 3 | abstract Dapper.ProviderTools.BulkCopy.AddColumnMapping(string! sourceColumn, string! destinationColumn) -> void 4 | abstract Dapper.ProviderTools.BulkCopy.DestinationTableName.get -> string! 5 | abstract Dapper.ProviderTools.BulkCopy.DestinationTableName.set -> void 6 | abstract Dapper.ProviderTools.BulkCopy.Dispose(bool disposing) -> void 7 | abstract Dapper.ProviderTools.BulkCopy.Wrapped.get -> object! 8 | abstract Dapper.ProviderTools.BulkCopy.WriteToServer(System.Data.DataRow![]! source) -> void 9 | abstract Dapper.ProviderTools.BulkCopy.WriteToServer(System.Data.DataTable! source) -> void 10 | abstract Dapper.ProviderTools.BulkCopy.WriteToServer(System.Data.IDataReader! source) -> void 11 | abstract Dapper.ProviderTools.BulkCopy.WriteToServerAsync(System.Data.Common.DbDataReader! source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! 12 | abstract Dapper.ProviderTools.BulkCopy.WriteToServerAsync(System.Data.DataRow![]! source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! 13 | abstract Dapper.ProviderTools.BulkCopy.WriteToServerAsync(System.Data.DataTable! source, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task! 14 | Dapper.ProviderTools.BulkCopy 15 | Dapper.ProviderTools.BulkCopy.BatchSize.get -> int 16 | Dapper.ProviderTools.BulkCopy.BatchSize.set -> void 17 | Dapper.ProviderTools.BulkCopy.BulkCopy() -> void 18 | Dapper.ProviderTools.BulkCopy.BulkCopyTimeout.get -> int 19 | Dapper.ProviderTools.BulkCopy.BulkCopyTimeout.set -> void 20 | Dapper.ProviderTools.BulkCopy.Dispose() -> void 21 | Dapper.ProviderTools.BulkCopy.EnableStreaming.get -> bool 22 | Dapper.ProviderTools.BulkCopy.EnableStreaming.set -> void 23 | Dapper.ProviderTools.DbConnectionExtensions 24 | Dapper.ProviderTools.DbExceptionExtensions 25 | static Dapper.ProviderTools.BulkCopy.Create(System.Data.Common.DbConnection! connection) -> Dapper.ProviderTools.BulkCopy! 26 | static Dapper.ProviderTools.BulkCopy.TryCreate(System.Data.Common.DbConnection! connection) -> Dapper.ProviderTools.BulkCopy? 27 | static Dapper.ProviderTools.DbConnectionExtensions.TryClearAllPools(this System.Data.Common.DbConnection! connection) -> bool 28 | static Dapper.ProviderTools.DbConnectionExtensions.TryClearPool(this System.Data.Common.DbConnection! connection) -> bool 29 | static Dapper.ProviderTools.DbConnectionExtensions.TryGetClientConnectionId(this System.Data.Common.DbConnection! connection, out System.Guid clientConnectionId) -> bool 30 | static Dapper.ProviderTools.DbExceptionExtensions.IsNumber(this System.Data.Common.DbException! exception, int number) -> bool -------------------------------------------------------------------------------- /Dapper.ProviderTools/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable -------------------------------------------------------------------------------- /Dapper.Rainbow/Dapper.Rainbow.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Dapper.Rainbow 4 | orm;sql;micro-orm 5 | Dapper.Rainbow 6 | Trivial micro-orm implemented on Dapper, provides with CRUD helpers. 7 | Sam Saffron 8 | 2017 Sam Saffron 9 | net461;netstandard2.0;net5.0 10 | 11 | false 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Dapper.Rainbow/IgnorePropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dapper 4 | { 5 | /// 6 | /// Specifies whether a property should be ignored for database operations. 7 | /// 8 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 9 | public class IgnorePropertyAttribute : Attribute 10 | { 11 | /// 12 | /// Specifies whether a property should be ignored for database operations. 13 | /// 14 | /// Whether to ignore this property. 15 | public IgnorePropertyAttribute(bool ignore) 16 | { 17 | Value = ignore; 18 | } 19 | 20 | /// 21 | /// Whether to ignore this property. 22 | /// 23 | public bool Value { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Dapper.Rainbow/SqlCompactDatabase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Common; 4 | using System.Linq; 5 | 6 | namespace Dapper 7 | { 8 | /// 9 | /// A SQL Compact specific implementation. 10 | /// 11 | /// The type of database. 12 | public abstract class SqlCompactDatabase : Database where TDatabase : Database, new() 13 | { 14 | /// 15 | /// A SQL Compact specific table, which handles the syntax correctly across operations. 16 | /// 17 | /// The type in the table. 18 | public class SqlCompactTable : Table 19 | { 20 | /// 21 | /// Creates a table for a SQL Compact database. 22 | /// 23 | /// 24 | /// 25 | public SqlCompactTable(Database database, string likelyTableName) 26 | : base(database, likelyTableName) 27 | { 28 | } 29 | 30 | /// 31 | /// Insert a row into the db 32 | /// 33 | /// Either DynamicParameters or an anonymous type or concrete type 34 | /// 35 | public override int? Insert(dynamic data) 36 | { 37 | var o = (object)data; 38 | List paramNames = GetParamNames(o); 39 | paramNames.Remove("Id"); 40 | 41 | string cols = string.Join(",", paramNames); 42 | string colsParams = string.Join(",", paramNames.Select(p => "@" + p)); 43 | 44 | var sql = "insert " + TableName + " (" + cols + ") values (" + colsParams + ")"; 45 | if (database.Execute(sql, o) != 1) 46 | { 47 | return null; 48 | } 49 | 50 | return (int)database.Query("SELECT @@IDENTITY AS LastInsertedId").Single(); 51 | } 52 | } 53 | 54 | /// 55 | /// Initializes the databases. 56 | /// 57 | /// The connection to use. 58 | /// The newly created database. 59 | public static TDatabase Init(DbConnection connection) 60 | { 61 | var db = new TDatabase(); 62 | db.InitDatabase(connection, 0); 63 | return db; 64 | } 65 | 66 | internal override Action CreateTableConstructorForTable() 67 | { 68 | return CreateTableConstructor(typeof(SqlCompactTable<>)); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Dapper.Rainbow/readme.md: -------------------------------------------------------------------------------- 1 | # Using Dapper.Rainbow in C# for CRUD Operations 2 | 3 | This guide outlines how to use `Dapper.Rainbow` in C# for CRUD operations. 4 | 5 | ## 1. Setting Up 6 | 7 | Add Dapper and Dapper.Rainbow to your project via NuGet: 8 | 9 | ```powershell 10 | Install-Package Dapper -Version x.x.x 11 | Install-Package Dapper.Rainbow -Version x.x.x 12 | ``` 13 | 14 | *Replace `x.x.x` with the latest version numbers.* 15 | 16 | ## 2. Database Setup and Requirements 17 | 18 | For `Dapper.Rainbow` to function correctly, ensure each table has a primary key column named `Id`. 19 | 20 | Example `Users` table schema: 21 | 22 | ```sql 23 | CREATE TABLE Users ( 24 | Id INT IDENTITY(1,1) PRIMARY KEY, 25 | Name VARCHAR(100), 26 | Email VARCHAR(100) 27 | ); 28 | ``` 29 | 30 | ## 3. Establishing Database Connection 31 | 32 | Open a connection to your database: 33 | 34 | ```csharp 35 | using System.Data.SqlClient; 36 | 37 | var connectionString = "your_connection_string_here"; 38 | using var connection = new SqlConnection(connectionString); 39 | connection.Open(); // Open the connection 40 | ``` 41 | 42 | ## 4. Defining Your Database Context 43 | 44 | Define a class for your database context: 45 | 46 | ```csharp 47 | using Dapper; 48 | using System.Data; 49 | 50 | public class MyDatabase : Database 51 | { 52 | public Table Users { get; set; } 53 | } 54 | 55 | public class User 56 | { 57 | public int Id { get; set; } 58 | public string Name { get; set; } 59 | public string Email { get; set; } 60 | } 61 | ``` 62 | 63 | ## 5. Performing CRUD Operations 64 | 65 | ### Insert 66 | 67 | ```csharp 68 | var db = new MyDatabase { Connection = connection }; 69 | var newUser = new User { Name = "John Doe", Email = "john.doe@example.com" }; 70 | var insertedUser = db.Users.Insert(newUser); 71 | ``` 72 | 73 | ### Select 74 | 75 | Fetch users by ID or all users: 76 | 77 | ```csharp 78 | var user = db.Users.Get(id); // Single user by ID 79 | var users = connection.Query("SELECT * FROM Users"); // All users 80 | ``` 81 | 82 | ### Update 83 | 84 | ```csharp 85 | var userToUpdate = db.Users.Get(id); 86 | userToUpdate.Email = "new.email@example.com"; 87 | db.Users.Update(userToUpdate); 88 | ``` 89 | 90 | ### Delete 91 | 92 | ```csharp 93 | db.Users.Delete(id); 94 | ``` 95 | 96 | ## 6. Working with Foreign Keys 97 | 98 | Example schema for a `Posts` table with a foreign key to `Users`: 99 | 100 | ```sql 101 | CREATE TABLE Posts ( 102 | Id INT IDENTITY(1,1) PRIMARY KEY, 103 | UserId INT, 104 | Content VARCHAR(255), 105 | FOREIGN KEY (UserId) REFERENCES Users(Id) 106 | ); 107 | ``` 108 | 109 | Inserting a parent (`User`) and a child (`Post`) row: 110 | 111 | ```csharp 112 | var newUser = new User { Name = "Jane Doe", Email = "jane.doe@example.com" }; 113 | var userId = db.Users.Insert(newUser); 114 | 115 | var newPost = new Post { UserId = userId, Content = "Hello, World!" }; 116 | db.Connection.Insert(newPost); // Using Dapper for the child table 117 | ``` 118 | 119 | -------------------------------------------------------------------------------- /Dapper.SqlBuilder/Dapper.SqlBuilder.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Dapper.SqlBuilder 4 | orm;sql;micro-orm;query;sql-builder 5 | Dapper SqlBuilder component 6 | The Dapper SqlBuilder component, for building SQL queries dynamically. 7 | Sam Saffron, Johan Danforth 8 | net461;netstandard2.0;net8.0 9 | false 10 | false 11 | enable 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Dapper.SqlBuilder/PublicAPI.Shipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | Dapper.SqlBuilder 3 | Dapper.SqlBuilder.AddClause(string! name, string! sql, object? parameters, string! joiner, string! prefix = "", string! postfix = "", bool isInclusive = false) -> Dapper.SqlBuilder! 4 | Dapper.SqlBuilder.AddParameters(dynamic! parameters) -> Dapper.SqlBuilder! 5 | Dapper.SqlBuilder.AddTemplate(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder.Template! 6 | Dapper.SqlBuilder.GroupBy(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 7 | Dapper.SqlBuilder.Having(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 8 | Dapper.SqlBuilder.InnerJoin(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 9 | Dapper.SqlBuilder.Intersect(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 10 | Dapper.SqlBuilder.Join(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 11 | Dapper.SqlBuilder.LeftJoin(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 12 | Dapper.SqlBuilder.OrderBy(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 13 | Dapper.SqlBuilder.OrWhere(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 14 | Dapper.SqlBuilder.RightJoin(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 15 | Dapper.SqlBuilder.Select(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 16 | Dapper.SqlBuilder.Set(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! 17 | Dapper.SqlBuilder.SqlBuilder() -> void 18 | Dapper.SqlBuilder.Template 19 | Dapper.SqlBuilder.Template.Parameters.get -> object? 20 | Dapper.SqlBuilder.Template.RawSql.get -> string! 21 | Dapper.SqlBuilder.Template.Template(Dapper.SqlBuilder! builder, string! sql, dynamic? parameters) -> void 22 | Dapper.SqlBuilder.Where(string! sql, dynamic? parameters = null) -> Dapper.SqlBuilder! -------------------------------------------------------------------------------- /Dapper.SqlBuilder/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable -------------------------------------------------------------------------------- /Dapper.StrongName/Dapper.StrongName.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Dapper.StrongName 4 | orm;sql;micro-orm 5 | Dapper (Strong Named) 6 | A high performance Micro-ORM supporting SQL Server, MySQL, Sqlite, SqlCE, Firebird etc. Major Sponsor: Dapper Plus from ZZZ Projects. 7 | Sam Saffron;Marc Gravell;Nick Craver 8 | net461;netstandard2.0;net8.0 9 | true 10 | true 11 | enable 12 | true 13 | $(DefineConstants);STRONG_NAME 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Dapper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DapperLib/Dapper/00b1023f292c436eb9830b3383fde68e177a13bf/Dapper.png -------------------------------------------------------------------------------- /Dapper.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | CE 3 | SQ 4 | SQL 5 | TVP -------------------------------------------------------------------------------- /Dapper.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DapperLib/Dapper/00b1023f292c436eb9830b3383fde68e177a13bf/Dapper.snk -------------------------------------------------------------------------------- /Dapper/CommandFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dapper 4 | { 5 | /// 6 | /// Additional state flags that control command behaviour 7 | /// 8 | [Flags] 9 | public enum CommandFlags 10 | { 11 | /// 12 | /// No additional flags 13 | /// 14 | None = 0, 15 | /// 16 | /// Should data be buffered before returning? 17 | /// 18 | Buffered = 1, 19 | /// 20 | /// Can async queries be pipelined? 21 | /// 22 | Pipelined = 2, 23 | /// 24 | /// Should the plan cache be bypassed? 25 | /// 26 | NoCache = 4, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Dapper/CompiledRegex.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace Dapper; 5 | 6 | internal static partial class CompiledRegex 7 | { 8 | #if DEBUG && NET7_0_OR_GREATER // enables colorization in IDE 9 | [StringSyntax("Regex")] 10 | #endif 11 | private const string 12 | WhitespaceOrReservedPattern = @"[\s;/\-+*]|^vacuum$|^commit$|^rollback$|^revert$", 13 | LegacyParameterPattern = @"(? LegacyParameterGen(); 32 | internal static Regex LiteralTokens => LiteralTokensGen(); 33 | internal static Regex PseudoPositional => PseudoPositionalGen(); 34 | internal static Regex WhitespaceOrReserved => WhitespaceOrReservedGen(); 35 | #else 36 | internal static Regex LegacyParameter { get; } 37 | = new(LegacyParameterPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled); 38 | internal static Regex LiteralTokens { get; } 39 | = new(LiteralTokensPattern, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant | RegexOptions.Compiled); 40 | internal static Regex PseudoPositional { get; } 41 | = new(PseudoPositionalPattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled); 42 | internal static Regex WhitespaceOrReserved { get; } 43 | = new(WhitespaceOrReservedPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase); 44 | #endif 45 | } 46 | -------------------------------------------------------------------------------- /Dapper/CustomPropertyTypeMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Dapper 5 | { 6 | /// 7 | /// Implements custom property mapping by user provided criteria (usually presence of some custom attribute with column to member mapping) 8 | /// 9 | public sealed class CustomPropertyTypeMap : SqlMapper.ITypeMap 10 | { 11 | private readonly Type _type; 12 | private readonly Func _propertySelector; 13 | 14 | /// 15 | /// Creates custom property mapping 16 | /// 17 | /// Target entity type 18 | /// Property selector based on target type and DataReader column name 19 | public CustomPropertyTypeMap(Type type, Func propertySelector) 20 | { 21 | _type = type ?? throw new ArgumentNullException(nameof(type)); 22 | _propertySelector = propertySelector ?? throw new ArgumentNullException(nameof(propertySelector)); 23 | } 24 | 25 | /// 26 | /// Always returns default constructor 27 | /// 28 | /// DataReader column names 29 | /// DataReader column types 30 | /// Default constructor 31 | public ConstructorInfo? FindConstructor(string[] names, Type[] types) => 32 | _type.GetConstructor(Array.Empty())!; 33 | 34 | /// 35 | /// Always returns null 36 | /// 37 | /// 38 | public ConstructorInfo? FindExplicitConstructor() => null; 39 | 40 | /// 41 | /// Not implemented as far as default constructor used for all cases 42 | /// 43 | /// 44 | /// 45 | /// 46 | public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName) 47 | { 48 | throw new NotSupportedException(); 49 | } 50 | 51 | /// 52 | /// Returns property based on selector strategy 53 | /// 54 | /// DataReader column name 55 | /// Property member map 56 | public SqlMapper.IMemberMap? GetMember(string columnName) 57 | { 58 | var prop = _propertySelector(_type, columnName); 59 | return prop is not null ? new SimpleMemberMap(columnName, prop) : null; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Dapper/Dapper.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Dapper 4 | Dapper 5 | orm;sql;micro-orm 6 | A high performance Micro-ORM supporting SQL Server, MySQL, Sqlite, SqlCE, Firebird etc. Major Sponsor: Dapper Plus from ZZZ Projects. 7 | Sam Saffron;Marc Gravell;Nick Craver 8 | net461;netstandard2.0;net8.0 9 | enable 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Dapper/DataTableHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | namespace Dapper 4 | { 5 | internal sealed class DataTableHandler : SqlMapper.ITypeHandler 6 | { 7 | public object Parse(Type destinationType, object value) 8 | { 9 | throw new NotImplementedException(); 10 | } 11 | 12 | public void SetValue(IDbDataParameter parameter, object value) 13 | { 14 | TableValuedParameter.Set(parameter, value as DataTable, null); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Dapper/DynamicParameters.CachedOutputSetters.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace Dapper 4 | { 5 | public partial class DynamicParameters 6 | { 7 | // The type here is used to differentiate the cache by type via generics 8 | // ReSharper disable once UnusedTypeParameter 9 | internal static class CachedOutputSetters 10 | { 11 | // Intentional, abusing generics to get our cache splits 12 | // ReSharper disable once StaticMemberInGenericType 13 | public static readonly Hashtable Cache = new Hashtable(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Dapper/DynamicParameters.ParamInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | 4 | namespace Dapper 5 | { 6 | public partial class DynamicParameters 7 | { 8 | private sealed class ParamInfo 9 | { 10 | public string Name { get; set; } = null!; 11 | public object? Value { get; set; } 12 | public ParameterDirection ParameterDirection { get; set; } 13 | public DbType? DbType { get; set; } 14 | public int? Size { get; set; } 15 | public IDbDataParameter AttachedParam { get; set; } = null!; 16 | internal Action? OutputCallback { get; set; } 17 | internal object OutputTarget { get; set; } = null!; 18 | internal bool CameFromTemplate { get; set; } 19 | 20 | public byte? Precision { get; set; } 21 | public byte? Scale { get; set; } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Dapper/ExplicitConstructorAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dapper 4 | { 5 | /// 6 | /// Tell Dapper to use an explicit constructor, passing nulls or 0s for all parameters 7 | /// 8 | /// 9 | /// Usage on methods is limited to the usage with Dapper.AOT (https://github.com/DapperLib/DapperAOT) 10 | /// 11 | [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method, AllowMultiple = false)] 12 | public sealed class ExplicitConstructorAttribute : Attribute 13 | { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Dapper/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace Dapper 5 | { 6 | internal static class Extensions 7 | { 8 | /// 9 | /// Creates a with a less specific generic parameter that perfectly mirrors the 10 | /// state of the specified . 11 | /// 12 | internal static Task CastResult(this Task task) 13 | where TFrom : TTo 14 | { 15 | if (task is null) throw new ArgumentNullException(nameof(task)); 16 | 17 | if (task.Status == TaskStatus.RanToCompletion) 18 | return Task.FromResult((TTo)task.Result); 19 | 20 | var source = new TaskCompletionSource(); 21 | task.ContinueWith(OnTaskCompleted, state: source, TaskContinuationOptions.ExecuteSynchronously); 22 | return source.Task; 23 | } 24 | 25 | private static void OnTaskCompleted(Task completedTask, object? state) 26 | where TFrom : TTo 27 | { 28 | var source = (TaskCompletionSource)state!; 29 | 30 | switch (completedTask.Status) 31 | { 32 | case TaskStatus.RanToCompletion: 33 | source.SetResult(completedTask.Result); 34 | break; 35 | case TaskStatus.Canceled: 36 | source.SetCanceled(); 37 | break; 38 | case TaskStatus.Faulted: 39 | source.SetException(completedTask.Exception!.InnerExceptions); 40 | break; 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Dapper/FeatureSupport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | 4 | namespace Dapper 5 | { 6 | /// 7 | /// Handles variances in features per DBMS 8 | /// 9 | internal class FeatureSupport 10 | { 11 | private static readonly FeatureSupport 12 | Default = new FeatureSupport(false), 13 | Postgres = new FeatureSupport(true), 14 | ClickHouse = new FeatureSupport(true); 15 | 16 | /// 17 | /// Gets the feature set based on the passed connection 18 | /// 19 | /// The connection to get supported features for. 20 | public static FeatureSupport Get(IDbConnection? connection) 21 | { 22 | string? name = connection?.GetType().Name; 23 | if (string.Equals(name, "npgsqlconnection", StringComparison.OrdinalIgnoreCase)) return Postgres; 24 | if (string.Equals(name, "clickhouseconnection", StringComparison.OrdinalIgnoreCase)) return ClickHouse; 25 | return Default; 26 | } 27 | 28 | private FeatureSupport(bool arrays) 29 | { 30 | Arrays = arrays; 31 | } 32 | 33 | /// 34 | /// True if the db supports array columns e.g. Postgresql 35 | /// 36 | public bool Arrays { get; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Dapper/Global.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | #if !STRONG_NAME 3 | [assembly: InternalsVisibleTo("Dapper.Tests")] 4 | #endif 5 | -------------------------------------------------------------------------------- /Dapper/NRT.cs: -------------------------------------------------------------------------------- 1 | #if !NET5_0_OR_GREATER 2 | namespace System.Diagnostics.CodeAnalysis 3 | { 4 | [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] 5 | internal sealed class NotNullWhenAttribute : Attribute 6 | { 7 | public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; 8 | 9 | public bool ReturnValue { get; } 10 | } 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /Dapper/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | [module: System.Runtime.CompilerServices.SkipLocalsInit] 2 | 3 | #if !NET5_0_OR_GREATER 4 | namespace System.Runtime.CompilerServices 5 | { 6 | [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] 7 | internal sealed class SkipLocalsInitAttribute : Attribute {} 8 | } 9 | namespace System.Diagnostics.CodeAnalysis 10 | { 11 | [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] 12 | internal sealed class MemberNotNullAttribute : Attribute 13 | { 14 | public MemberNotNullAttribute(string member) {} 15 | public MemberNotNullAttribute(params string[] members) {} 16 | } 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /Dapper/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable -------------------------------------------------------------------------------- /Dapper/PublicAPI/net461/PublicAPI.Shipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable -------------------------------------------------------------------------------- /Dapper/PublicAPI/net461/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable -------------------------------------------------------------------------------- /Dapper/PublicAPI/net8.0/PublicAPI.Shipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | -------------------------------------------------------------------------------- /Dapper/PublicAPI/net8.0/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable -------------------------------------------------------------------------------- /Dapper/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable -------------------------------------------------------------------------------- /Dapper/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt: -------------------------------------------------------------------------------- 1 | #nullable enable -------------------------------------------------------------------------------- /Dapper/SimpleMemberMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Dapper 5 | { 6 | /// 7 | /// Represents simple member map for one of target parameter or property or field to source DataReader column 8 | /// 9 | internal sealed class SimpleMemberMap : SqlMapper.IMemberMap 10 | { 11 | /// 12 | /// Creates instance for simple property mapping 13 | /// 14 | /// DataReader column name 15 | /// Target property 16 | public SimpleMemberMap(string columnName, PropertyInfo property) 17 | { 18 | ColumnName = columnName ?? throw new ArgumentNullException(nameof(columnName)); 19 | Property = property ?? throw new ArgumentNullException(nameof(property)); 20 | } 21 | 22 | /// 23 | /// Creates instance for simple field mapping 24 | /// 25 | /// DataReader column name 26 | /// Target property 27 | public SimpleMemberMap(string columnName, FieldInfo field) 28 | { 29 | ColumnName = columnName ?? throw new ArgumentNullException(nameof(columnName)); 30 | Field = field ?? throw new ArgumentNullException(nameof(field)); 31 | } 32 | 33 | /// 34 | /// Creates instance for simple constructor parameter mapping 35 | /// 36 | /// DataReader column name 37 | /// Target constructor parameter 38 | public SimpleMemberMap(string columnName, ParameterInfo parameter) 39 | { 40 | ColumnName = columnName ?? throw new ArgumentNullException(nameof(columnName)); 41 | Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter)); 42 | } 43 | 44 | /// 45 | /// DataReader column name 46 | /// 47 | public string ColumnName { get; } 48 | 49 | /// 50 | /// Target member type 51 | /// 52 | public Type MemberType => Field?.FieldType ?? Property?.PropertyType ?? Parameter?.ParameterType!; 53 | 54 | /// 55 | /// Target property 56 | /// 57 | public PropertyInfo? Property { get; } 58 | 59 | /// 60 | /// Target field 61 | /// 62 | public FieldInfo? Field { get; } 63 | 64 | /// 65 | /// Target constructor parameter 66 | /// 67 | public ParameterInfo? Parameter { get; } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Dapper/SqlDataRecordHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | 5 | namespace Dapper 6 | { 7 | internal sealed class SqlDataRecordHandler : SqlMapper.ITypeHandler 8 | where T : IDataRecord 9 | { 10 | public object Parse(Type destinationType, object value) 11 | { 12 | throw new NotSupportedException(); 13 | } 14 | 15 | public void SetValue(IDbDataParameter parameter, object value) 16 | { 17 | SqlDataRecordListTVPParameter.Set(parameter, value as IEnumerable, null); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.CacheInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Data.Common; 4 | using System.Threading; 5 | 6 | namespace Dapper 7 | { 8 | public static partial class SqlMapper 9 | { 10 | private class CacheInfo 11 | { 12 | public DeserializerState Deserializer { get; set; } 13 | public Func[]? OtherDeserializers { get; set; } 14 | public Action? ParamReader { get; set; } 15 | private int hitCount; 16 | public int GetHitCount() { return Interlocked.CompareExchange(ref hitCount, 0, 0); } 17 | public void RecordHit() { Interlocked.Increment(ref hitCount); } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.DapperTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Dapper 5 | { 6 | public static partial class SqlMapper 7 | { 8 | private sealed class DapperTable 9 | { 10 | private string[] fieldNames; 11 | private readonly Dictionary fieldNameLookup; 12 | 13 | internal string[] FieldNames => fieldNames; 14 | 15 | public DapperTable(string[] fieldNames) 16 | { 17 | this.fieldNames = fieldNames ?? throw new ArgumentNullException(nameof(fieldNames)); 18 | 19 | fieldNameLookup = new Dictionary(fieldNames.Length, StringComparer.Ordinal); 20 | // if there are dups, we want the **first** key to be the "winner" - so iterate backwards 21 | for (int i = fieldNames.Length - 1; i >= 0; i--) 22 | { 23 | string key = fieldNames[i]; 24 | if (key is not null) fieldNameLookup[key] = i; 25 | } 26 | } 27 | 28 | internal int IndexOfName(string name) 29 | { 30 | return (name is not null && fieldNameLookup.TryGetValue(name, out int result)) ? result : -1; 31 | } 32 | 33 | internal int AddField(string name) 34 | { 35 | if (name is null) throw new ArgumentNullException(nameof(name)); 36 | if (fieldNameLookup.ContainsKey(name)) throw new InvalidOperationException("Field already exists: " + name); 37 | int oldLen = fieldNames.Length; 38 | Array.Resize(ref fieldNames, oldLen + 1); // yes, this is sub-optimal, but this is not the expected common case 39 | fieldNames[oldLen] = name; 40 | fieldNameLookup[name] = oldLen; 41 | return oldLen; 42 | } 43 | 44 | internal bool FieldExists(string key) => key is not null && fieldNameLookup.ContainsKey(key); 45 | 46 | public int FieldCount => fieldNames.Length; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.DeserializerState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Data.Common; 4 | 5 | namespace Dapper 6 | { 7 | public static partial class SqlMapper 8 | { 9 | private readonly struct DeserializerState 10 | { 11 | public readonly int Hash; 12 | public readonly Func Func; 13 | 14 | public DeserializerState(int hash, Func func) 15 | { 16 | Hash = hash; 17 | Func = func; 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.DontMap.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper 2 | { 3 | public static partial class SqlMapper 4 | { 5 | /// 6 | /// Dummy type for excluding from multi-map 7 | /// 8 | private class DontMap { /* hiding constructor */ } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.ICustomQueryParameter.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | 3 | namespace Dapper 4 | { 5 | public static partial class SqlMapper 6 | { 7 | /// 8 | /// Implement this interface to pass an arbitrary db specific parameter to Dapper 9 | /// 10 | public interface ICustomQueryParameter 11 | { 12 | /// 13 | /// Add the parameter needed to the command before it executes 14 | /// 15 | /// The raw command prior to execution 16 | /// Parameter name 17 | void AddParameter(IDbCommand command, string name); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.IDynamicParameters.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | 3 | namespace Dapper 4 | { 5 | public static partial class SqlMapper 6 | { 7 | /// 8 | /// Implement this interface to pass an arbitrary db specific set of parameters to Dapper 9 | /// 10 | public interface IDynamicParameters 11 | { 12 | /// 13 | /// Add all the parameters needed to the command just before it executes 14 | /// 15 | /// The raw command prior to execution 16 | /// Information about the query 17 | void AddParameters(IDbCommand command, Identity identity); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.IMemberMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Dapper 5 | { 6 | public static partial class SqlMapper 7 | { 8 | /// 9 | /// Implements this interface to provide custom member mapping 10 | /// 11 | public interface IMemberMap 12 | { 13 | /// 14 | /// Source DataReader column name 15 | /// 16 | string ColumnName { get; } 17 | 18 | /// 19 | /// Target member type 20 | /// 21 | Type MemberType { get; } 22 | 23 | /// 24 | /// Target property 25 | /// 26 | PropertyInfo? Property { get; } 27 | 28 | /// 29 | /// Target field 30 | /// 31 | FieldInfo? Field { get; } 32 | 33 | /// 34 | /// Target constructor parameter 35 | /// 36 | ParameterInfo? Parameter { get; } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.IParameterCallbacks.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper 2 | { 3 | public static partial class SqlMapper 4 | { 5 | /// 6 | /// Extends IDynamicParameters with facilities for executing callbacks after commands have completed 7 | /// 8 | public interface IParameterCallbacks : IDynamicParameters 9 | { 10 | /// 11 | /// Invoked when the command has executed 12 | /// 13 | void OnCompleted(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.IParameterLookup.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper 2 | { 3 | public static partial class SqlMapper 4 | { 5 | /// 6 | /// Extends IDynamicParameters providing by-name lookup of parameter values 7 | /// 8 | public interface IParameterLookup : IDynamicParameters 9 | { 10 | /// 11 | /// Get the value of the specified parameter (return null if not found) 12 | /// 13 | /// The name of the parameter to get. 14 | object? this[string name] { get; } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.ITypeHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | 4 | namespace Dapper 5 | { 6 | public static partial class SqlMapper 7 | { 8 | /// 9 | /// Implement this interface to perform custom type-based parameter handling and value parsing 10 | /// 11 | public interface ITypeHandler 12 | { 13 | /// 14 | /// Assign the value of a parameter before a command executes 15 | /// 16 | /// The parameter to configure 17 | /// Parameter value 18 | void SetValue(IDbDataParameter parameter, object value); 19 | 20 | /// 21 | /// Parse a database value back to a typed value 22 | /// 23 | /// The value from the database 24 | /// The type to parse to 25 | /// The typed value 26 | object? Parse(Type destinationType, object value); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.ITypeMap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Dapper 5 | { 6 | public static partial class SqlMapper 7 | { 8 | /// 9 | /// Implement this interface to change default mapping of reader columns to type members 10 | /// 11 | public interface ITypeMap 12 | { 13 | /// 14 | /// Finds best constructor 15 | /// 16 | /// DataReader column names 17 | /// DataReader column types 18 | /// Matching constructor or default one 19 | ConstructorInfo? FindConstructor(string[] names, Type[] types); 20 | 21 | /// 22 | /// Returns a constructor which should *always* be used. 23 | /// 24 | /// Parameters will be default values, nulls for reference types and zero'd for value types. 25 | /// 26 | /// Use this class to force object creation away from parameterless constructors you don't control. 27 | /// 28 | ConstructorInfo? FindExplicitConstructor(); 29 | 30 | /// 31 | /// Gets mapping for constructor parameter 32 | /// 33 | /// Constructor to resolve 34 | /// DataReader column name 35 | /// Mapping implementation 36 | IMemberMap? GetConstructorParameter(ConstructorInfo constructor, string columnName); 37 | 38 | /// 39 | /// Gets member mapping for column 40 | /// 41 | /// DataReader column name 42 | /// Mapping implementation 43 | IMemberMap? GetMember(string columnName); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.Link.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using System.Threading; 3 | 4 | namespace Dapper 5 | { 6 | public static partial class SqlMapper 7 | { 8 | /// 9 | /// This is a micro-cache; suitable when the number of terms is controllable (a few hundred, for example), 10 | /// and strictly append-only; you cannot change existing values. All key matches are on **REFERENCE** 11 | /// equality. The type is fully thread-safe. 12 | /// 13 | /// The type to cache. 14 | /// The value type of the cache. 15 | internal class Link where TKey : class 16 | { 17 | public static void Clear(ref Link? head) => Interlocked.Exchange(ref head, null); 18 | public static bool TryGet(Link? link, TKey key, [NotNullWhen(true)] out TValue? value) 19 | { 20 | while (link is not null) 21 | { 22 | if ((object)key == (object)link.Key) 23 | { 24 | value = link.Value!; 25 | return true; 26 | } 27 | link = link.Tail; 28 | } 29 | value = default; 30 | return false; 31 | } 32 | 33 | public static bool TryAdd(ref Link? head, TKey key, ref TValue value) 34 | { 35 | bool tryAgain; 36 | do 37 | { 38 | var snapshot = Interlocked.CompareExchange(ref head, null, null); 39 | if (TryGet(snapshot, key, out TValue? found)) 40 | { // existing match; report the existing value instead 41 | value = found; 42 | return false; 43 | } 44 | var newNode = new Link(key, value, snapshot); 45 | // did somebody move our cheese? 46 | tryAgain = Interlocked.CompareExchange(ref head, newNode, snapshot) != snapshot; 47 | } while (tryAgain); 48 | return true; 49 | } 50 | 51 | private Link(TKey key, TValue value, Link? tail) 52 | { 53 | Key = key; 54 | Value = value; 55 | Tail = tail; 56 | } 57 | 58 | public TKey Key { get; } 59 | public TValue Value { get; } 60 | public Link? Tail { get; } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.LiteralToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Dapper 5 | { 6 | public static partial class SqlMapper 7 | { 8 | /// 9 | /// Represents a placeholder for a value that should be replaced as a literal value in the resulting sql 10 | /// 11 | internal readonly struct LiteralToken 12 | { 13 | /// 14 | /// The text in the original command that should be replaced 15 | /// 16 | public string Token { get; } 17 | 18 | /// 19 | /// The name of the member referred to by the token 20 | /// 21 | public string Member { get; } 22 | 23 | internal LiteralToken(string token, string member) 24 | { 25 | Token = token; 26 | Member = member; 27 | } 28 | 29 | internal static IList None => Array.Empty(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.TypeHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | 4 | namespace Dapper 5 | { 6 | public static partial class SqlMapper 7 | { 8 | /// 9 | /// Base-class for simple type-handlers 10 | /// 11 | /// This this handler is for. 12 | public abstract class TypeHandler : ITypeHandler 13 | { 14 | /// 15 | /// Assign the value of a parameter before a command executes 16 | /// 17 | /// The parameter to configure 18 | /// Parameter value 19 | public abstract void SetValue(IDbDataParameter parameter, T? value); 20 | 21 | /// 22 | /// Parse a database value back to a typed value 23 | /// 24 | /// The value from the database 25 | /// The typed value 26 | public abstract T? Parse(object value); 27 | 28 | void ITypeHandler.SetValue(IDbDataParameter parameter, object value) 29 | { 30 | if (value is DBNull) 31 | { 32 | parameter.Value = value; 33 | } 34 | else 35 | { 36 | SetValue(parameter, (T?)value); 37 | } 38 | } 39 | 40 | object? ITypeHandler.Parse(Type destinationType, object value) 41 | { 42 | return Parse(value); 43 | } 44 | } 45 | 46 | /// 47 | /// Base-class for simple type-handlers that are based around strings 48 | /// 49 | /// This this handler is for. 50 | public abstract class StringTypeHandler : TypeHandler 51 | { 52 | /// 53 | /// Parse a string into the expected type (the string will never be null) 54 | /// 55 | /// The string to parse. 56 | protected abstract T Parse(string xml); 57 | 58 | /// 59 | /// Format an instance into a string (the instance will never be null) 60 | /// 61 | /// The string to format. 62 | protected abstract string Format(T xml); 63 | 64 | /// 65 | /// Assign the value of a parameter before a command executes 66 | /// 67 | /// The parameter to configure 68 | /// Parameter value 69 | public override void SetValue(IDbDataParameter parameter, T? value) 70 | { 71 | parameter.Value = value is null ? (object)DBNull.Value : Format(value); 72 | } 73 | 74 | /// 75 | /// Parse a database value back to a typed value 76 | /// 77 | /// The value from the database 78 | /// The typed value 79 | public override T Parse(object value) 80 | { 81 | if (value is null || value is DBNull) return default!; 82 | return Parse((string)value); 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Dapper/SqlMapper.TypeHandlerCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Data; 4 | 5 | namespace Dapper 6 | { 7 | public static partial class SqlMapper 8 | { 9 | /// 10 | /// Not intended for direct usage 11 | /// 12 | /// The type to have a cache for. 13 | [Obsolete(ObsoleteInternalUsageOnly, false)] 14 | [Browsable(false)] 15 | [EditorBrowsable(EditorBrowsableState.Never)] 16 | public static class TypeHandlerCache 17 | { 18 | /// 19 | /// Not intended for direct usage. 20 | /// 21 | /// The object to parse. 22 | [Obsolete(ObsoleteInternalUsageOnly, true)] 23 | public static T? Parse(object value) => (T?)handler.Parse(typeof(T), value); 24 | 25 | /// 26 | /// Not intended for direct usage. 27 | /// 28 | /// The parameter to set a value for. 29 | /// The value to set. 30 | [Obsolete(ObsoleteInternalUsageOnly, true)] 31 | public static void SetValue(IDbDataParameter parameter, object value) => handler.SetValue(parameter, value); 32 | 33 | internal static void SetHandler(ITypeHandler handler) 34 | { 35 | TypeHandlerCache.handler = handler; 36 | } 37 | 38 | private static ITypeHandler handler = null!; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Dapper/TableValuedParameter.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | 3 | namespace Dapper 4 | { 5 | /// 6 | /// Used to pass a DataTable as a TableValuedParameter 7 | /// 8 | internal sealed class TableValuedParameter : SqlMapper.ICustomQueryParameter 9 | { 10 | private readonly DataTable table; 11 | private readonly string? typeName; 12 | 13 | /// 14 | /// Create a new instance of . 15 | /// 16 | /// The to create this parameter for 17 | public TableValuedParameter(DataTable table) : this(table, null) { /* run base */ } 18 | 19 | /// 20 | /// Create a new instance of . 21 | /// 22 | /// The to create this parameter for. 23 | /// The name of the type this parameter is for. 24 | public TableValuedParameter(DataTable table, string? typeName) 25 | { 26 | this.table = table; 27 | this.typeName = typeName; 28 | } 29 | 30 | void SqlMapper.ICustomQueryParameter.AddParameter(IDbCommand command, string name) 31 | { 32 | var param = command.CreateParameter(); 33 | param.ParameterName = name; 34 | Set(param, table, typeName); 35 | command.Parameters.Add(param); 36 | } 37 | 38 | internal static void Set(IDbDataParameter parameter, DataTable? table, string? typeName) 39 | { 40 | #pragma warning disable 0618 41 | parameter.Value = SqlMapper.SanitizeParameterValue(table); 42 | #pragma warning restore 0618 43 | if (string.IsNullOrEmpty(typeName) && table is not null) 44 | { 45 | typeName = table.GetTypeName(); 46 | } 47 | if (!string.IsNullOrEmpty(typeName)) StructuredHelper.ConfigureTVP(parameter, typeName); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Dapper/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace Dapper 5 | { 6 | internal static class TypeExtensions 7 | { 8 | public static MethodInfo? GetPublicInstanceMethod(this Type type, string name, Type[] types) 9 | => type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public, null, types, null); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Dapper/UdtTypeHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | 4 | namespace Dapper 5 | { 6 | public static partial class SqlMapper 7 | { 8 | /// 9 | /// A type handler for data-types that are supported by the underlying provider, but which need 10 | /// a well-known UdtTypeName to be specified 11 | /// 12 | public class UdtTypeHandler : ITypeHandler 13 | { 14 | private readonly string udtTypeName; 15 | /// 16 | /// Creates a new instance of UdtTypeHandler with the specified . 17 | /// 18 | /// The user defined type name. 19 | public UdtTypeHandler(string udtTypeName) 20 | { 21 | if (string.IsNullOrEmpty(udtTypeName)) throw new ArgumentException("Cannot be null or empty", udtTypeName); 22 | this.udtTypeName = udtTypeName; 23 | } 24 | 25 | object? ITypeHandler.Parse(Type destinationType, object value) 26 | { 27 | return value is DBNull ? null : value; 28 | } 29 | 30 | void ITypeHandler.SetValue(IDbDataParameter parameter, object value) 31 | { 32 | #pragma warning disable 0618 33 | parameter.Value = SanitizeParameterValue(value); 34 | #pragma warning restore 0618 35 | if(!(value is DBNull)) StructuredHelper.ConfigureUDT(parameter, udtTypeName); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Dapper/WrappedDataReader.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | 3 | namespace Dapper 4 | { 5 | /// 6 | /// Describes a reader that controls the lifetime of both a command and a reader, 7 | /// exposing the downstream command/reader as properties. 8 | /// 9 | public interface IWrappedDataReader : IDataReader 10 | { 11 | /// 12 | /// Obtain the underlying reader 13 | /// 14 | IDataReader Reader { get; } 15 | /// 16 | /// Obtain the underlying command 17 | /// 18 | IDbCommand Command { get; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Dapper/XmlHandlers.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Xml; 3 | using System.Xml.Linq; 4 | 5 | namespace Dapper 6 | { 7 | internal abstract class XmlTypeHandler : SqlMapper.StringTypeHandler 8 | { 9 | public override void SetValue(IDbDataParameter parameter, T? value) 10 | { 11 | base.SetValue(parameter, value); 12 | parameter.DbType = DbType.Xml; 13 | } 14 | } 15 | 16 | internal sealed class XmlDocumentHandler : XmlTypeHandler 17 | { 18 | protected override XmlDocument Parse(string xml) 19 | { 20 | var doc = new XmlDocument(); 21 | doc.LoadXml(xml); 22 | return doc; 23 | } 24 | 25 | protected override string Format(XmlDocument xml) => xml.OuterXml; 26 | } 27 | 28 | internal sealed class XDocumentHandler : XmlTypeHandler 29 | { 30 | protected override XDocument Parse(string xml) => XDocument.Parse(xml); 31 | protected override string Format(XDocument xml) => xml.ToString(); 32 | } 33 | 34 | internal sealed class XElementHandler : XmlTypeHandler 35 | { 36 | protected override XElement Parse(string xml) => XElement.Parse(xml); 37 | protected override string Format(XElement xml) => xml.ToString(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2019 Stack Exchange, Inc. 4 | 5 | true 6 | true 7 | ../Dapper.snk 8 | 9 | $(AssemblyName) 10 | https://dapperlib.github.io/Dapper/ 11 | https://github.com/DapperLib/Dapper 12 | Apache-2.0 13 | Dapper.png 14 | git 15 | https://github.com/DapperLib/Dapper 16 | false 17 | $(NOWARN);IDE0056;IDE0057;IDE0079 18 | true 19 | embedded 20 | en-US 21 | false 22 | true 23 | true 24 | 13 25 | false 26 | true 27 | readme.md 28 | true 29 | 30 | 31 | 32 | true 33 | true 34 | true 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)')) 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- 1 | The Dapper library and tools are licenced under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0 2 | 3 | The Dapper logo is copyright Marc Gravell 2021 onwards; it is fine to use the Dapper logo when referencing the Dapper library and utilities, but 4 | the Dapper logo (including derivatives) must not be used in a way that misrepresents an external product or library as being affiliated or endorsed 5 | with Dapper. For example, you must not use the Dapper logo as the package icon on your own external tool (even if it uses Dapper internally), 6 | without written permission. If in doubt: ask. -------------------------------------------------------------------------------- /NonCLA.md: -------------------------------------------------------------------------------- 1 | # Dapper - the "Non CLA" CLA 2 | 3 | IANAL. YANAL (I hope). Let's keep this simple; if you want to contribute to Dapper, great! Let's just check a few things for the record. 4 | 5 | By accepting this agreement, you're saying: 6 | 7 | ## You're allowed to contribute this code 8 | 9 | The code needs to be yours (without being owned by some employer, etc), or contributed with the owner's knowledge and permission, or 10 | in accordance with a licence that clearly allows the code to be reused in line with this project's licence (http://www.apache.org/licenses/LICENSE-2.0), 11 | and in that last case: a cross-reference back to the origin would be nice. 12 | 13 | (for the pedants: "licence" and "license" to be used interchangeably here; language is fun) 14 | 15 | ## It isn't "your code" any more 16 | 17 | Contributed code belongs to the Dapper project, not you the contributor. That means 18 | Dapper can use it, not use it, remove it, or 19 | edit it in any way - *even changing the spacing and variable names*. I know: shocking. 20 | 21 | ## No backsies 22 | 23 | Contributing code to Dapper is permanent; you can't later demand that we remove your code because... well, anything. Even if one 24 | of the maintainers wears socks that look *really ugly*. 25 | 26 | ## For gratis 27 | 28 | Contributing code to Dapper gets you the bugfix or feature or whatever that you want; you have our thanks and appreciation, but unless we've 29 | agreed something separately: that's it. No turning up unannounced at the tri-annual BBQ, or demanding... again, anything. 30 | 31 | --- 32 | 33 | That's it. Basically "don't make our life harder". 34 | 35 | Thanks! 36 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2022 2 | 3 | skip_branch_with_pr: true 4 | skip_tags: true 5 | skip_commits: 6 | files: 7 | - '**/*.md' 8 | 9 | environment: 10 | Appveyor: true 11 | # Postgres 12 | POSTGRES_PATH: C:\Program Files\PostgreSQL\16 13 | PGUSER: postgres 14 | PGPASSWORD: Password12! 15 | POSTGRES_ENV_POSTGRES_USER: postgres 16 | POSTGRES_ENV_POSTGRES_PASSWORD: Password12! 17 | POSTGRES_ENV_POSTGRES_DB: test 18 | # MySQL 19 | MYSQL_PATH: C:\Program Files\MySQL\MySQL Server 8.0 20 | MYSQL_PWD: Password12! 21 | MYSQL_ENV_MYSQL_USER: root 22 | MYSQL_ENV_MYSQL_PASSWORD: Password12! 23 | MYSQL_ENV_MYSQL_DATABASE: test 24 | # Connection strings for tests: 25 | MySqlConnectionString: Server=localhost;Database=test;Uid=root;Pwd=Password12! 26 | OLEDBConnectionString: Provider=SQLOLEDB;Data Source=(local)\SQL2019;Initial Catalog=tempdb;User Id=sa;Password=Password12! 27 | PostgesConnectionString: Server=localhost;Port=5432;User Id=postgres;Password=Password12!;Database=test 28 | SqlServerConnectionString: Server=(local)\SQL2019;Database=tempdb;User ID=sa;Password=Password12! 29 | 30 | init: 31 | - git config --global core.autocrlf input 32 | - SET PATH=%POSTGRES_PATH%\bin;%MYSQL_PATH%\bin;%PATH% 33 | - net start MSSQL$SQL2019 34 | - net start postgresql-x64-16 35 | - ps: Start-Service MySQL80 36 | 37 | nuget: 38 | disable_publish_on_pr: true 39 | 40 | before_build: 41 | # Postgres 42 | - createdb test 43 | # MySQL 44 | - '"C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql" -e "create database test;" --user=root' 45 | 46 | build_script: 47 | # Our stuff 48 | - ps: .\build.ps1 -PullRequestNumber "$env:APPVEYOR_PULL_REQUEST_NUMBER" -CreatePackages $true 49 | 50 | test: off 51 | artifacts: 52 | - path: .\.nupkgs\*.nupkg 53 | 54 | deploy: 55 | - provider: NuGet 56 | server: https://www.myget.org/F/stackoverflow/api/v2 57 | on: 58 | branch: main 59 | api_key: 60 | secure: P/UHxq2DEs0GI1SoDXDesHjRVsSVgdywz5vmsnhFQQY5aJgO3kP+QfhwfhXz19Rw 61 | symbol_server: https://www.myget.org/F/stackoverflow/symbols/api/v2/package 62 | - provider: NuGet 63 | server: https://www.myget.org/F/dapper/api/v2 64 | on: 65 | branch: main 66 | api_key: 67 | secure: PV7ERAltWWLhy7AT2h+Vb5c1BM9/WFgvggb+rKyQ8hDg3fYqpZauYdidOOgt2lp4 68 | symbol_server: https://www.myget.org/F/dapper/api/v2/package -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.Belgrade.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using Belgrade.SqlClient.SqlDb; 3 | using Belgrade.SqlClient; 4 | using System.ComponentModel; 5 | using System.Threading.Tasks; 6 | 7 | namespace Dapper.Tests.Performance 8 | { 9 | [Description("Belgrade")] 10 | public class BelgradeBenchmarks : BenchmarkBase 11 | { 12 | private QueryMapper _mapper; 13 | 14 | [GlobalSetup] 15 | public void Setup() 16 | { 17 | BaseSetup(); 18 | _mapper = new QueryMapper(ConnectionString); 19 | } 20 | 21 | [Benchmark(Description = "FirstOrDefault")] 22 | public Task FirstOrDefault() 23 | { 24 | Step(); 25 | return _mapper.Sql("SELECT TOP 1 * FROM Posts WHERE Id = @Id").Param("Id", i).FirstOrDefault( 26 | reader => new Post 27 | { 28 | Id = reader.GetInt32(0), 29 | Text = reader.GetString(1), 30 | CreationDate = reader.GetDateTime(2), 31 | LastChangeDate = reader.GetDateTime(3), 32 | 33 | Counter1 = reader.IsDBNull(4) ? null : (int?)reader.GetInt32(4), 34 | Counter2 = reader.IsDBNull(5) ? null : (int?)reader.GetInt32(5), 35 | Counter3 = reader.IsDBNull(6) ? null : (int?)reader.GetInt32(6), 36 | Counter4 = reader.IsDBNull(7) ? null : (int?)reader.GetInt32(7), 37 | Counter5 = reader.IsDBNull(8) ? null : (int?)reader.GetInt32(8), 38 | Counter6 = reader.IsDBNull(9) ? null : (int?)reader.GetInt32(9), 39 | Counter7 = reader.IsDBNull(10) ? null : (int?)reader.GetInt32(10), 40 | Counter8 = reader.IsDBNull(11) ? null : (int?)reader.GetInt32(11), 41 | Counter9 = reader.IsDBNull(12) ? null : (int?)reader.GetInt32(12), 42 | }); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.Dapper.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using Dapper.Contrib.Extensions; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | 6 | namespace Dapper.Tests.Performance 7 | { 8 | [Description("Dapper")] 9 | public class DapperBenchmarks : BenchmarkBase 10 | { 11 | [GlobalSetup] 12 | public void Setup() 13 | { 14 | BaseSetup(); 15 | } 16 | 17 | [Benchmark(Description = "Query (buffered)")] 18 | public Post QueryBuffered() 19 | { 20 | Step(); 21 | return _connection.Query("select * from Posts where Id = @Id", new { Id = i }, buffered: true).First(); 22 | } 23 | 24 | [Benchmark(Description = "Query (buffered)")] 25 | public dynamic QueryBufferedDynamic() 26 | { 27 | Step(); 28 | return _connection.Query("select * from Posts where Id = @Id", new { Id = i }, buffered: true).First(); 29 | } 30 | 31 | [Benchmark(Description = "Query (unbuffered)")] 32 | public Post QueryUnbuffered() 33 | { 34 | Step(); 35 | return _connection.Query("select * from Posts where Id = @Id", new { Id = i }, buffered: false).First(); 36 | } 37 | 38 | [Benchmark(Description = "Query (unbuffered)")] 39 | public dynamic QueryUnbufferedDynamic() 40 | { 41 | Step(); 42 | return _connection.Query("select * from Posts where Id = @Id", new { Id = i }, buffered: false).First(); 43 | } 44 | 45 | [Benchmark(Description = "QueryFirstOrDefault")] 46 | public Post QueryFirstOrDefault() 47 | { 48 | Step(); 49 | return _connection.QueryFirstOrDefault("select * from Posts where Id = @Id", new { Id = i }); 50 | } 51 | 52 | [Benchmark(Description = "QueryFirstOrDefault")] 53 | public dynamic QueryFirstOrDefaultDynamic() 54 | { 55 | Step(); 56 | return _connection.QueryFirstOrDefault("select * from Posts where Id = @Id", new { Id = i }).First(); 57 | } 58 | 59 | [Benchmark(Description = "Contrib Get")] 60 | public Post ContribGet() 61 | { 62 | Step(); 63 | return _connection.Get(i); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.Dashing.cs: -------------------------------------------------------------------------------- 1 | #if NET4X 2 | using System.ComponentModel; 3 | using BenchmarkDotNet.Attributes; 4 | using Dapper.Tests.Performance.Dashing; 5 | using Dashing; 6 | 7 | namespace Dapper.Tests.Performance 8 | { 9 | [Description("Dashing")] 10 | public class DashingBenchmarks : BenchmarkBase 11 | { 12 | private ISession Session; 13 | 14 | [GlobalSetup] 15 | public void Setup() 16 | { 17 | BaseSetup(); 18 | var configuration = new DashingConfiguration(); 19 | var database = new SqlDatabase(configuration, ConnectionString); 20 | Session = database.BeginTransactionLessSession(_connection); 21 | } 22 | 23 | // This needs love to be compatible with current SDKs (weaving doesn't work and shouldn't be used here anyway (competition). 24 | // I'll file an issue with Dashing to see if someone can help me out here since I can't figure out from the docs how to 25 | // make it work correctly. 26 | //[Benchmark(Description = "Get")] 27 | public Dashing.Post Get() 28 | { 29 | Step(); 30 | return Session.Get(i); 31 | } 32 | } 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.EntityFramework.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System.ComponentModel; 3 | using System.Linq; 4 | 5 | namespace Dapper.Tests.Performance 6 | { 7 | [Description("EF 6")] 8 | public class EF6Benchmarks : BenchmarkBase 9 | { 10 | private EntityFramework.EFContext Context; 11 | 12 | [GlobalSetup] 13 | public void Setup() 14 | { 15 | BaseSetup(); 16 | Context = new EntityFramework.EFContext(_connection); 17 | } 18 | 19 | [Benchmark(Description = "First")] 20 | public Post First() 21 | { 22 | Step(); 23 | return Context.Posts.First(p => p.Id == i); 24 | } 25 | 26 | [Benchmark(Description = "SqlQuery")] 27 | public Post SqlQuery() 28 | { 29 | Step(); 30 | return Context.Database.SqlQuery("select * from Posts where Id = {0}", i).First(); 31 | } 32 | 33 | [Benchmark(Description = "First (No Tracking)")] 34 | public Post NoTracking() 35 | { 36 | Step(); 37 | return Context.Posts.AsNoTracking().First(p => p.Id == i); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.EntityFrameworkCore.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using Dapper.Tests.Performance.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore; 4 | using System; 5 | using System.ComponentModel; 6 | using System.Linq; 7 | 8 | namespace Dapper.Tests.Performance 9 | { 10 | [Description("EF Core")] 11 | public class EFCoreBenchmarks : BenchmarkBase 12 | { 13 | private EFCoreContext Context; 14 | 15 | private static readonly Func compiledQuery = 16 | EF.CompileQuery((EFCoreContext ctx, int id) => ctx.Posts.First(p => p.Id == id)); 17 | 18 | [GlobalSetup] 19 | public void Setup() 20 | { 21 | BaseSetup(); 22 | Context = new EFCoreContext(ConnectionString); 23 | } 24 | 25 | [Benchmark(Description = "First")] 26 | public Post First() 27 | { 28 | Step(); 29 | return Context.Posts.First(p => p.Id == i); 30 | } 31 | 32 | [Benchmark(Description = "First (Compiled)")] 33 | public Post Compiled() 34 | { 35 | Step(); 36 | return compiledQuery(Context, i); 37 | } 38 | 39 | [Benchmark(Description = "SqlQuery")] 40 | public Post SqlQuery() 41 | { 42 | Step(); 43 | return Context.Posts.FromSqlRaw("select * from Posts where Id = {0}", i).First(); 44 | } 45 | 46 | [Benchmark(Description = "First (No Tracking)")] 47 | public Post NoTracking() 48 | { 49 | Step(); 50 | return Context.Posts.AsNoTracking().First(p => p.Id == i); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.HandCoded.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using Microsoft.Data.SqlClient; 6 | 7 | namespace Dapper.Tests.Performance 8 | { 9 | [Description("Hand Coded")] 10 | public class HandCodedBenchmarks : BenchmarkBase 11 | { 12 | private SqlCommand _postCommand; 13 | private SqlParameter _idParam; 14 | private DataTable _table; 15 | 16 | [GlobalSetup] 17 | public void Setup() 18 | { 19 | BaseSetup(); 20 | _postCommand = new SqlCommand("select Top 1 * from Posts where Id = @Id", _connection); 21 | _idParam = _postCommand.Parameters.Add("@Id", SqlDbType.Int); 22 | _postCommand.Prepare(); 23 | _table = new DataTable 24 | { 25 | Columns = 26 | { 27 | {"Id", typeof (int)}, 28 | {"Text", typeof (string)}, 29 | {"CreationDate", typeof (DateTime)}, 30 | {"LastChangeDate", typeof (DateTime)}, 31 | {"Counter1", typeof (int)}, 32 | {"Counter2", typeof (int)}, 33 | {"Counter3", typeof (int)}, 34 | {"Counter4", typeof (int)}, 35 | {"Counter5", typeof (int)}, 36 | {"Counter6", typeof (int)}, 37 | {"Counter7", typeof (int)}, 38 | {"Counter8", typeof (int)}, 39 | {"Counter9", typeof (int)}, 40 | } 41 | }; 42 | } 43 | 44 | [Benchmark(Description = "SqlCommand")] 45 | public Post SqlCommand() 46 | { 47 | Step(); 48 | _idParam.Value = i; 49 | 50 | using (var reader = _postCommand.ExecuteReader(CommandBehavior.SingleResult | CommandBehavior.SingleRow)) 51 | { 52 | reader.Read(); 53 | return new Post 54 | { 55 | Id = reader.GetInt32(0), 56 | Text = reader.GetNullableString(1), 57 | CreationDate = reader.GetDateTime(2), 58 | LastChangeDate = reader.GetDateTime(3), 59 | 60 | Counter1 = reader.GetNullableValue(4), 61 | Counter2 = reader.GetNullableValue(5), 62 | Counter3 = reader.GetNullableValue(6), 63 | Counter4 = reader.GetNullableValue(7), 64 | Counter5 = reader.GetNullableValue(8), 65 | Counter6 = reader.GetNullableValue(9), 66 | Counter7 = reader.GetNullableValue(10), 67 | Counter8 = reader.GetNullableValue(11), 68 | Counter9 = reader.GetNullableValue(12) 69 | }; 70 | } 71 | } 72 | 73 | [Benchmark(Description = "DataTable")] 74 | public dynamic DataTableDynamic() 75 | { 76 | Step(); 77 | _idParam.Value = i; 78 | _table.Rows.Clear(); 79 | var values = new object[13]; 80 | using (var reader = _postCommand.ExecuteReader(CommandBehavior.SingleResult | CommandBehavior.SingleRow)) 81 | { 82 | reader.Read(); 83 | reader.GetValues(values); 84 | return _table.Rows.Add(values); 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.Linq2DB.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | using System; 4 | using System.Linq; 5 | using Dapper.Tests.Performance.Linq2Db; 6 | using LinqToDB; 7 | using LinqToDB.Data; 8 | using System.ComponentModel; 9 | 10 | namespace Dapper.Tests.Performance 11 | { 12 | [Description("LINQ to DB")] 13 | public class LinqToDBBenchmarks : BenchmarkBase // note To not 2 because the "2" confuses BDN CLI 14 | { 15 | private Linq2DBContext _dbContext; 16 | 17 | private static readonly Func compiledQuery = CompiledQuery.Compile((Linq2DBContext db, int id) => db.Posts.First(c => c.Id == id)); 18 | 19 | [GlobalSetup] 20 | public void Setup() 21 | { 22 | BaseSetup(); 23 | DataConnection.DefaultSettings = new Linq2DBSettings(_connection.ConnectionString); 24 | _dbContext = new Linq2DBContext(); 25 | } 26 | 27 | [Benchmark(Description = "First")] 28 | public Post First() 29 | { 30 | Step(); 31 | return _dbContext.Posts.First(p => p.Id == i); 32 | } 33 | 34 | [Benchmark(Description = "First (Compiled)")] 35 | public Post Compiled() 36 | { 37 | Step(); 38 | return compiledQuery(_dbContext, i); 39 | } 40 | 41 | [Benchmark(Description = "Query")] 42 | public Post Query() 43 | { 44 | Step(); 45 | return _dbContext.Query("select * from Posts where Id = @id", new { id = i }).First(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.Linq2Sql.cs: -------------------------------------------------------------------------------- 1 | #if NET4X 2 | using BenchmarkDotNet.Attributes; 3 | using Dapper.Tests.Performance.Linq2Sql; 4 | using System; 5 | using System.ComponentModel; 6 | using System.Data.Linq; 7 | using System.Linq; 8 | 9 | namespace Dapper.Tests.Performance 10 | { 11 | [Description("LINQ to SQL")] 12 | public class LinqToSqlBenchmarks : BenchmarkBase // note To not 2 because the "2" confuses BDN CLI 13 | { 14 | private DataClassesDataContext Linq2SqlContext; 15 | 16 | private static readonly Func compiledQuery = 17 | CompiledQuery.Compile((DataClassesDataContext ctx, int id) => ctx.Posts.First(p => p.Id == id)); 18 | 19 | [GlobalSetup] 20 | public void Setup() 21 | { 22 | BaseSetup(); 23 | Linq2SqlContext = new DataClassesDataContext(_connection); 24 | } 25 | 26 | [Benchmark(Description = "First")] 27 | public Linq2Sql.Post First() 28 | { 29 | Step(); 30 | return Linq2SqlContext.Posts.First(p => p.Id == i); 31 | } 32 | 33 | [Benchmark(Description = "First (Compiled)")] 34 | public Linq2Sql.Post Compiled() 35 | { 36 | Step(); 37 | return compiledQuery(Linq2SqlContext, i); 38 | } 39 | 40 | [Benchmark(Description = "ExecuteQuery")] 41 | public Post ExecuteQuery() 42 | { 43 | Step(); 44 | return Linq2SqlContext.ExecuteQuery("select * from Posts where Id = {0}", i).First(); 45 | } 46 | } 47 | } 48 | #endif 49 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.Massive.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using Massive; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | 6 | namespace Dapper.Tests.Performance 7 | { 8 | [Description("Massive")] 9 | public class MassiveBenchmarks : BenchmarkBase 10 | { 11 | private DynamicModel _model; 12 | 13 | [GlobalSetup] 14 | public void Setup() 15 | { 16 | BaseSetup(); 17 | RegisterSqlFactory(); 18 | _model = new DynamicModel(ConnectionString); 19 | } 20 | 21 | [Benchmark(Description = "Query (dynamic)")] 22 | public dynamic QueryDynamic() 23 | { 24 | Step(); 25 | return _model.Query("select * from Posts where Id = @0", _connection, i).First(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.Mighty.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using Mighty; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | 6 | namespace Dapper.Tests.Performance 7 | { 8 | [Description("Mighty")] 9 | public class MightyBenchmarks : BenchmarkBase 10 | { 11 | private MightyOrm _model; 12 | private MightyOrm _dynamicModel; 13 | 14 | [GlobalSetup] 15 | public void Setup() 16 | { 17 | BaseSetup(); 18 | 19 | // Mighty needs the connection string to contain the ProviderName in addition to everything else for Reasons. 20 | // However, it appears the SQL Server driver chokes on it if it's in the full connection string, so we programatically add it here. 21 | var connectionString = $"{ConnectionStringSettings.ConnectionString};ProviderName={ConnectionStringSettings.ProviderName}"; 22 | 23 | _model = new MightyOrm(connectionString); 24 | _dynamicModel = new MightyOrm(connectionString); 25 | } 26 | 27 | [Benchmark(Description = "Query")] 28 | public Post Query() 29 | { 30 | Step(); 31 | return _model.Query("select * from Posts where Id = @0", _connection, i).First(); 32 | } 33 | 34 | [Benchmark(Description = "Query")] 35 | public dynamic QueryDynamic() 36 | { 37 | Step(); 38 | return _dynamicModel.Query("select * from Posts where Id = @0", _connection, i).First(); 39 | } 40 | 41 | [Benchmark(Description = "SingleFromQuery")] 42 | public Post SingleFromQuery() 43 | { 44 | Step(); 45 | return _model.SingleFromQuery("select * from Posts where Id = @0", _connection, i); 46 | } 47 | 48 | [Benchmark(Description = "SingleFromQuery")] 49 | public dynamic SingleFromQueryDynamic() 50 | { 51 | Step(); 52 | return _dynamicModel.SingleFromQuery("select * from Posts where Id = @0", _connection, i); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.NHibernate.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using Dapper.Tests.Performance.NHibernate; 3 | using NHibernate; 4 | using NHibernate.Criterion; 5 | using NHibernate.Linq; 6 | using NHibernate.Transform; 7 | using NHibernate.Util; 8 | using System.Linq; 9 | 10 | namespace Dapper.Tests.Performance 11 | { 12 | public class NHibernateBenchmarks : BenchmarkBase 13 | { 14 | private IStatelessSession _sql, _hql, _criteria, _linq, _get; 15 | 16 | [GlobalSetup] 17 | public void Setup() 18 | { 19 | BaseSetup(); 20 | _sql = NHibernateHelper.OpenSession(); 21 | _hql = NHibernateHelper.OpenSession(); 22 | _criteria = NHibernateHelper.OpenSession(); 23 | _linq = NHibernateHelper.OpenSession(); 24 | _get = NHibernateHelper.OpenSession(); 25 | } 26 | 27 | [Benchmark(Description = "SQL")] 28 | public Post SQL() 29 | { 30 | Step(); 31 | return _sql.CreateSQLQuery("select * from Posts where Id = :id") 32 | .SetInt32("id", i) 33 | .SetResultTransformer(Transformers.AliasToBean()) 34 | .List()[0]; 35 | } 36 | 37 | [Benchmark(Description = "HQL")] 38 | public Post HQL() 39 | { 40 | Step(); 41 | return _hql.CreateQuery("from Post as p where p.Id = :id") 42 | .SetInt32("id", i) 43 | .List()[0]; 44 | } 45 | 46 | [Benchmark(Description = "Criteria")] 47 | public Post Criteria() 48 | { 49 | Step(); 50 | return _criteria.CreateCriteria() 51 | .Add(Restrictions.IdEq(i)) 52 | .List()[0]; 53 | } 54 | 55 | [Benchmark(Description = "LINQ")] 56 | public Post LINQ() 57 | { 58 | Step(); 59 | return _linq.Query().First(p => p.Id == i); 60 | } 61 | 62 | [Benchmark(Description = "Get")] 63 | public Post Get() 64 | { 65 | Step(); 66 | return _get.Get(i); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.Norm.cs: -------------------------------------------------------------------------------- 1 | #if !NET4X 2 | using BenchmarkDotNet.Attributes; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using Norm; 6 | using System; 7 | 8 | namespace Dapper.Tests.Performance 9 | { 10 | [Description("Norm")] 11 | public class NormBenchmarks : BenchmarkBase 12 | { 13 | [GlobalSetup] 14 | public void Setup() 15 | { 16 | BaseSetup(); 17 | } 18 | 19 | [Benchmark(Description = "Read<> (class)")] 20 | public Post Read() 21 | { 22 | Step(); 23 | return _connection.Read("select * from Posts where Id = @Id", i).First(); 24 | } 25 | 26 | [Benchmark(Description = "Read<> (tuples)")] 27 | public (int, string, DateTime, DateTime, int?, int?, int?, int?, int?, int?, int?, int?) ReadSimpleValues() 28 | { 29 | Step(); 30 | return _connection.Read("select * from Posts where Id = @Id", i).First(); 31 | } 32 | 33 | [Benchmark(Description = "Read<()> (named tuples)")] 34 | public (int Id, string Text, DateTime CreationDate, DateTime LastChangeDate, int? Counter1, int? Counter2, int? Counter3, int? Counter4, int? Counter5, int? Counter6, int? Counter7, int? Counter8) ReadTuple() 35 | { 36 | Step(); 37 | return _connection.Read<(int Id, string Text, DateTime CreationDate, DateTime LastChangeDate, int? Counter1, int? Counter2, int? Counter3, int? Counter4, int? Counter5, int? Counter6, int? Counter7, int? Counter8)>("select * from Posts where Id = @Id", i).First(); 38 | } 39 | } 40 | } 41 | #endif 42 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.RepoDB.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Linq; 3 | using BenchmarkDotNet.Attributes; 4 | using RepoDb; 5 | using RepoDb.DbHelpers; 6 | using RepoDb.DbSettings; 7 | using RepoDb.StatementBuilders; 8 | 9 | namespace Dapper.Tests.Performance 10 | { 11 | [Description("RepoDB")] 12 | public class RepoDbBenchmarks : BenchmarkBase 13 | { 14 | [GlobalSetup] 15 | public void Setup() 16 | { 17 | BaseSetup(); 18 | GlobalConfiguration.Setup().UseSqlServer(); 19 | 20 | // We need this since benchmarks using System.Data.SqlClient 21 | var dbSetting = new SqlServerDbSetting(); 22 | DbSettingMapper 23 | .Add(dbSetting, true); 24 | DbHelperMapper 25 | .Add(new SqlServerDbHelper(), true); 26 | StatementBuilderMapper 27 | .Add(new SqlServerStatementBuilder(dbSetting), true); 28 | 29 | ClassMapper.Add("Posts"); 30 | } 31 | 32 | [Benchmark(Description = "Query")] 33 | public Post Query() 34 | { 35 | Step(); 36 | return _connection.Query(i).First(); 37 | } 38 | 39 | [Benchmark(Description = "QueryWhere")] 40 | public Post QueryWhere() 41 | { 42 | Step(); 43 | return _connection.Query(x => x.Id == i).First(); 44 | } 45 | 46 | [Benchmark(Description = "QueryDynamic")] 47 | public Post QueryDynamic() 48 | { 49 | Step(); 50 | return _connection.Query(new { Id = i }).First(); 51 | } 52 | 53 | [Benchmark(Description = "QueryField")] 54 | public Post QueryField() 55 | { 56 | Step(); 57 | return _connection.Query([new(nameof(Post.Id), i)]).First(); 58 | } 59 | 60 | [Benchmark(Description = "ExecuteQuery")] 61 | public Post ExecuteQuery() 62 | { 63 | Step(); 64 | return _connection.ExecuteQuery("select * from Posts where Id = @Id", new { Id = i }).First(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.ServiceStack.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using ServiceStack.OrmLite; 3 | using System.ComponentModel; 4 | using System.Data; 5 | 6 | namespace Dapper.Tests.Performance 7 | { 8 | [Description("ServiceStack")] 9 | public class ServiceStackBenchmarks : BenchmarkBase 10 | { 11 | private IDbConnection _db; 12 | 13 | [GlobalSetup] 14 | public void Setup() 15 | { 16 | BaseSetup(); 17 | var dbFactory = new OrmLiteConnectionFactory(ConnectionString, SqlServerDialect.Provider); 18 | _db = dbFactory.Open(); 19 | } 20 | 21 | [Benchmark(Description = "SingleById")] 22 | public Post Query() 23 | { 24 | Step(); 25 | return _db.SingleById(i); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.SqlMarshal.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System.ComponentModel; 3 | 4 | namespace Dapper.Tests.Performance 5 | { 6 | [Description("SqlMarshal")] 7 | public partial class SqlMarshalBenchmarks : BenchmarkBase 8 | { 9 | [GlobalSetup] 10 | public void Setup() 11 | { 12 | BaseSetup(); 13 | } 14 | 15 | [Benchmark(Description = "SqlCommand")] 16 | public Post SqlCommand() 17 | { 18 | Step(); 19 | return ReadPost("select Top 1 * from Posts where Id = @id", i); 20 | } 21 | 22 | [SqlMarshal("")] 23 | private partial Post ReadPost([RawSql]string sql, int id); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.Susanoo.cs: -------------------------------------------------------------------------------- 1 | #if NET4X 2 | using BenchmarkDotNet.Attributes; 3 | using Susanoo; 4 | using Susanoo.Processing; 5 | using System.ComponentModel; 6 | using System.Data; 7 | using System.Linq; 8 | 9 | namespace Dapper.Tests.Performance 10 | { 11 | [Description("Susanoo")] 12 | public class SusanooBenchmarks : BenchmarkBase 13 | { 14 | private DatabaseManager _db; 15 | 16 | private static readonly ISingleResultSetCommandProcessor _cmd = 17 | CommandManager.Instance.DefineCommand("SELECT * FROM Posts WHERE Id = @Id", CommandType.Text) 18 | .DefineResults() 19 | .Realize(); 20 | 21 | private static readonly ISingleResultSetCommandProcessor _cmdDynamic = 22 | CommandManager.Instance.DefineCommand("SELECT * FROM Posts WHERE Id = @Id", CommandType.Text) 23 | .DefineResults() 24 | .Realize(); 25 | 26 | [GlobalSetup] 27 | public void Setup() 28 | { 29 | BaseSetup(); 30 | _db = new DatabaseManager(_connection); 31 | } 32 | 33 | [Benchmark(Description = "Execute (Cache)")] 34 | public Post MappingCache() 35 | { 36 | Step(); 37 | return CommandManager.Instance.DefineCommand("SELECT * FROM Posts WHERE Id = @Id", CommandType.Text) 38 | .DefineResults() 39 | .Realize() 40 | .Execute(_db, new { Id = i }).First(); 41 | } 42 | 43 | [Benchmark(Description = "Execute (Cache)")] 44 | public dynamic MappingCacheDynamic() 45 | { 46 | Step(); 47 | return CommandManager.Instance.DefineCommand("SELECT * FROM Posts WHERE Id = @Id", CommandType.Text) 48 | .DefineResults() 49 | .Realize() 50 | .Execute(_db, new { Id = i }).First(); 51 | } 52 | 53 | [Benchmark(Description = "Execute (Static)")] 54 | public Post MappingStatic() 55 | { 56 | Step(); 57 | return _cmd.Execute(_db, new { Id = i }).First(); 58 | } 59 | 60 | [Benchmark(Description = "Execut (Static)")] 61 | public dynamic MappingStaticDynamic() 62 | { 63 | Step(); 64 | return _cmdDynamic.Execute(_db, new { Id = i }).First(); 65 | } 66 | } 67 | } 68 | #endif 69 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.XPO.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | using System; 4 | using System.Linq; 5 | using System.ComponentModel; 6 | using DevExpress.Xpo; 7 | using DevExpress.Data.Filtering; 8 | 9 | namespace Dapper.Tests.Performance 10 | { 11 | [Description("DevExpress.XPO")] 12 | public class XpoBenchmarks : BenchmarkBase 13 | { 14 | public UnitOfWork _session; 15 | 16 | [GlobalSetup] 17 | public void Setup() 18 | { 19 | BaseSetup(); 20 | IDataLayer dataLayer = XpoDefault.GetDataLayer(_connection, DevExpress.Xpo.DB.AutoCreateOption.SchemaAlreadyExists); 21 | dataLayer.Dictionary.GetDataStoreSchema(typeof(Xpo.Post)); 22 | _session = new UnitOfWork(dataLayer, dataLayer) 23 | { 24 | IdentityMapBehavior = IdentityMapBehavior.Strong 25 | }; 26 | _session.TypesManager.EnsureIsTypedObjectValid(); 27 | } 28 | 29 | [GlobalCleanup] 30 | public void Cleanup() 31 | { 32 | _session.Dispose(); 33 | } 34 | 35 | [Benchmark(Description = "GetObjectByKey")] 36 | public Xpo.Post GetObjectByKey() 37 | { 38 | Step(); 39 | return _session.GetObjectByKey(i, true); 40 | } 41 | 42 | [Benchmark(Description = "FindObject")] 43 | public Xpo.Post FindObject() 44 | { 45 | Step(); 46 | CriteriaOperator _findCriteria = new BinaryOperator() 47 | { 48 | OperatorType = BinaryOperatorType.Equal, 49 | LeftOperand = new OperandProperty("Id"), 50 | RightOperand = new ConstantValue(i) 51 | }; 52 | return _session.FindObject(_findCriteria); 53 | } 54 | 55 | [Benchmark(Description = "Query")] 56 | public Xpo.Post Query() 57 | { 58 | Step(); 59 | return _session.Query().First(p => p.Id == i); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Benchmarks.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | using System; 3 | using System.Configuration; 4 | using Microsoft.Data.SqlClient; 5 | 6 | namespace Dapper.Tests.Performance 7 | { 8 | [BenchmarkCategory("ORM")] 9 | public abstract class BenchmarkBase 10 | { 11 | protected static readonly Random _rand = new Random(); 12 | protected SqlConnection _connection; 13 | public static ConnectionStringSettings ConnectionStringSettings { get; } = ConfigurationManager.ConnectionStrings["Main"]; 14 | public static string ConnectionString { get; } = ConnectionStringSettings.ConnectionString; 15 | protected int i; 16 | 17 | protected void BaseSetup() 18 | { 19 | i = 0; 20 | _connection = new SqlConnection(ConnectionString); 21 | _connection.Open(); 22 | } 23 | 24 | protected void RegisterSqlFactory() 25 | { 26 | #if NETCOREAPP 27 | System.Data.Common.DbProviderFactories.RegisterFactory("System.Data.SqlClient", SqlClientFactory.Instance); 28 | #endif 29 | } 30 | 31 | protected void Step() 32 | { 33 | i++; 34 | if (i > 5000) i = 1; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Config.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Columns; 2 | using BenchmarkDotNet.Configs; 3 | using BenchmarkDotNet.Diagnosers; 4 | using BenchmarkDotNet.Exporters; 5 | using BenchmarkDotNet.Exporters.Csv; 6 | using BenchmarkDotNet.Jobs; 7 | using BenchmarkDotNet.Loggers; 8 | using BenchmarkDotNet.Order; 9 | using Dapper.Tests.Performance.Helpers; 10 | 11 | namespace Dapper.Tests.Performance 12 | { 13 | public class Config : ManualConfig 14 | { 15 | public const int Iterations = 500; 16 | 17 | public Config() 18 | { 19 | AddLogger(ConsoleLogger.Default); 20 | 21 | AddExporter(CsvExporter.Default); 22 | AddExporter(MarkdownExporter.GitHub); 23 | AddExporter(HtmlExporter.Default); 24 | 25 | var md = MemoryDiagnoser.Default; 26 | AddDiagnoser(md); 27 | AddColumn(new ORMColum()); 28 | AddColumn(TargetMethodColumn.Method); 29 | AddColumn(new ReturnColum()); 30 | AddColumn(StatisticColumn.Mean); 31 | AddColumn(StatisticColumn.StdDev); 32 | AddColumn(StatisticColumn.Error); 33 | AddColumn(BaselineRatioColumn.RatioMean); 34 | AddColumnProvider(DefaultColumnProviders.Metrics); 35 | 36 | AddJob(Job.ShortRun 37 | .WithLaunchCount(1) 38 | .WithWarmupCount(2) 39 | .WithUnrollFactor(Iterations) 40 | .WithIterationCount(10) 41 | ); 42 | Orderer = new DefaultOrderer(SummaryOrderPolicy.FastestToSlowest); 43 | Options |= ConfigOptions.JoinSummary; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Dapper.Tests.Performance 4 | Dapper Core Performance Suite 5 | Exe 6 | net462;net8.0 7 | false 8 | $(NoWarn);IDE0063;IDE0034;IDE0059;IDE0060 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | $(DefineConstants);NET4X 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/DapperCacheImpact.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using BenchmarkDotNet.Attributes; 3 | 4 | namespace Dapper.Tests.Performance 5 | { 6 | [Description("Dapper cache impact")] 7 | [MemoryDiagnoser] 8 | public class DapperCacheImpact : BenchmarkBase 9 | { 10 | [GlobalSetup] 11 | public void Setup() => BaseSetup(); 12 | 13 | private readonly object args = new { Id = 42, Name = "abc" }; 14 | 15 | public class Foo 16 | { 17 | public int Id { get; set; } 18 | public string Name { get; set; } 19 | } 20 | 21 | // note: custom BDN setup means [Params] is awkward; unroll manually instead 22 | [Benchmark] 23 | public void ExecuteNoParameters_Cache() => _connection.Execute(new CommandDefinition("select '42' as Id, 'abc' as Name", flags: CommandFlags.None)); 24 | [Benchmark] 25 | public void ExecuteParameters_Cache() => _connection.Execute(new CommandDefinition("select @id as Id, @name as Name", args, flags: CommandFlags.None)); 26 | [Benchmark] 27 | public void QueryFirstNoParameters_Cache() => _connection.QueryFirst(new CommandDefinition("select '42' as Id, 'abc' as Name", flags: CommandFlags.None)); 28 | [Benchmark] 29 | public void QueryFirstParameters_Cache() => _connection.QueryFirst(new CommandDefinition("select @id as Id, @name as Name", args, flags: CommandFlags.None)); 30 | [Benchmark] 31 | public void ExecuteNoParameters_NoCache() => _connection.Execute(new CommandDefinition("select '42' as Id, 'abc' as Name", flags: CommandFlags.NoCache)); 32 | [Benchmark] 33 | public void ExecuteParameters_NoCache() => _connection.Execute(new CommandDefinition("select @id as Id, @name as Name", args, flags: CommandFlags.NoCache)); 34 | [Benchmark] 35 | public void QueryFirstNoParameters_NoCache() => _connection.QueryFirst(new CommandDefinition("select '42' as Id, 'abc' as Name", flags: CommandFlags.NoCache)); 36 | [Benchmark] 37 | public void QueryFirstParameters_NoCache() => _connection.QueryFirst(new CommandDefinition("select @id as Id, @name as Name", args, flags: CommandFlags.NoCache)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Dashing/DashingConfiguration.cs: -------------------------------------------------------------------------------- 1 | using Dashing.Configuration; 2 | 3 | namespace Dapper.Tests.Performance.Dashing 4 | { 5 | public class DashingConfiguration : BaseConfiguration 6 | { 7 | public DashingConfiguration() 8 | { 9 | Add(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Dashing/Post.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dapper.Tests.Performance.Dashing 4 | { 5 | public class Post 6 | { 7 | public int Id { get; set; } 8 | public string Text { get; set; } 9 | public DateTime CreationDate { get; set; } 10 | public DateTime LastChangeDate { get; set; } 11 | public int? Counter1 { get; set; } 12 | public int? Counter2 { get; set; } 13 | public int? Counter3 { get; set; } 14 | public int? Counter4 { get; set; } 15 | public int? Counter5 { get; set; } 16 | public int? Counter6 { get; set; } 17 | public int? Counter7 { get; set; } 18 | public int? Counter8 { get; set; } 19 | public int? Counter9 { get; set; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/EntityFramework/EFContext.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | using System.Data.Entity; 3 | 4 | namespace Dapper.Tests.Performance.EntityFramework 5 | { 6 | public class EFContext : DbContext 7 | { 8 | public EFContext(DbConnection connection, bool owned = false) : base(connection, owned) 9 | { 10 | } 11 | 12 | public DbSet Posts { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/EntityFrameworkCore/EFCoreContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace Dapper.Tests.Performance.EntityFrameworkCore 4 | { 5 | public class EFCoreContext : DbContext 6 | { 7 | private readonly string _connectionString; 8 | 9 | public EFCoreContext(string connectionString) 10 | { 11 | _connectionString = connectionString; 12 | } 13 | 14 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(_connectionString); 15 | 16 | public DbSet Posts { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Helpers/ORMColum.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Reflection; 3 | using BenchmarkDotNet.Columns; 4 | using BenchmarkDotNet.Reports; 5 | using BenchmarkDotNet.Running; 6 | 7 | namespace Dapper.Tests.Performance.Helpers 8 | { 9 | public class ORMColum : IColumn 10 | { 11 | public string Id => nameof(ORMColum); 12 | public string ColumnName { get; } = "ORM"; 13 | public string Legend => "The object/relational mapper being tested"; 14 | 15 | public bool IsDefault(Summary summary, BenchmarkCase benchmarkCase) => false; 16 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase) 17 | { 18 | var type = benchmarkCase.Descriptor.WorkloadMethod.DeclaringType; 19 | return type.GetCustomAttribute()?.Description ?? type.Name.Replace("Benchmarks", string.Empty); 20 | } 21 | 22 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style) => GetValue(summary, benchmarkCase); 23 | 24 | public bool IsAvailable(Summary summary) => true; 25 | public bool AlwaysShow => true; 26 | public ColumnCategory Category => ColumnCategory.Job; 27 | public int PriorityInCategory => -10; 28 | public bool IsNumeric => false; 29 | public UnitType UnitType => UnitType.Dimensionless; 30 | public override string ToString() => ColumnName; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Helpers/ReturnColum.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Columns; 2 | using BenchmarkDotNet.Reports; 3 | using BenchmarkDotNet.Running; 4 | 5 | namespace Dapper.Tests.Performance.Helpers 6 | { 7 | public class ReturnColum : IColumn 8 | { 9 | public string Id => nameof(ReturnColum); 10 | public string ColumnName { get; } = "Return"; 11 | public string Legend => "The return type of the method"; 12 | 13 | public bool IsDefault(Summary summary, BenchmarkCase benchmarkCase) => false; 14 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase) 15 | { 16 | var type = benchmarkCase.Descriptor.WorkloadMethod.ReturnType; 17 | return type == typeof(object) ? "dynamic" : type.Name; 18 | } 19 | 20 | public string GetValue(Summary summary, BenchmarkCase benchmarkCase, SummaryStyle style) => GetValue(summary, benchmarkCase); 21 | 22 | public bool IsAvailable(Summary summary) => true; 23 | public bool AlwaysShow => true; 24 | public ColumnCategory Category => ColumnCategory.Job; 25 | public int PriorityInCategory => 1; 26 | public bool IsNumeric => false; 27 | public UnitType UnitType => UnitType.Dimensionless; 28 | public override string ToString() => ColumnName; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Linq2DB/ConnectionStringSettings.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB.Configuration; 2 | 3 | namespace Dapper.Tests.Performance.Linq2Db 4 | { 5 | public class ConnectionStringSettings : IConnectionStringSettings 6 | { 7 | public string ConnectionString { get; set; } 8 | public string Name { get; set; } 9 | public string ProviderName { get; set; } 10 | public bool IsGlobal => false; 11 | } 12 | } -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Linq2DB/Linq2DBContext.cs: -------------------------------------------------------------------------------- 1 | using LinqToDB; 2 | 3 | namespace Dapper.Tests.Performance.Linq2Db 4 | { 5 | public class Linq2DBContext : LinqToDB.Data.DataConnection 6 | { 7 | public ITable Posts => this.GetTable(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Linq2DB/Linq2DbSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using LinqToDB.Configuration; 4 | 5 | namespace Dapper.Tests.Performance.Linq2Db 6 | { 7 | public class Linq2DBSettings : ILinqToDBSettings 8 | { 9 | private readonly string _connectionString; 10 | public IEnumerable DataProviders => Enumerable.Empty(); 11 | 12 | public string DefaultConfiguration => "SqlServer"; 13 | public string DefaultDataProvider => "SqlServer"; 14 | 15 | public Linq2DBSettings(string connectionString) 16 | { 17 | _connectionString = connectionString; 18 | } 19 | 20 | public IEnumerable ConnectionStrings 21 | { 22 | get 23 | { 24 | yield return 25 | new ConnectionStringSettings 26 | { 27 | Name = "SqlServer", 28 | ProviderName = "SqlServer", 29 | ConnectionString = _connectionString 30 | }; 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Linq2Sql/DataClasses.dbml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
-------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Linq2Sql/DataClasses.dbml.layout: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/NHibernate/NHibernateHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using NHibernate; 3 | using NHibernate.Cfg; 4 | 5 | namespace Dapper.Tests.Performance.NHibernate 6 | { 7 | public static class NHibernateHelper 8 | { 9 | private static ISessionFactory _sessionFactory; 10 | 11 | private static ISessionFactory SessionFactory 12 | { 13 | get 14 | { 15 | if (_sessionFactory == null) 16 | { 17 | var configuration = new Configuration(); 18 | configuration.Configure(Assembly.GetExecutingAssembly(), "Dapper.Tests.Performance.NHibernate.hibernate.cfg.xml"); 19 | configuration.AddAssembly(typeof(Post).Assembly); 20 | _sessionFactory = configuration.BuildSessionFactory(); 21 | } 22 | 23 | return _sessionFactory; 24 | } 25 | } 26 | 27 | public static IStatelessSession OpenSession() 28 | { 29 | return SessionFactory.OpenStatelessSession(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/NHibernate/Post.hbm.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/NHibernate/hibernate.cfg.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | NHibernate.Connection.DriverConnectionProvider 5 | NHibernate.Dialect.MsSql2005Dialect 6 | NHibernate.Driver.SqlClientDriver 7 | Main 8 | false 9 | 10 | 11 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/Post.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dapper.Tests.Performance 4 | { 5 | [ServiceStack.DataAnnotations.Alias("Posts")] 6 | [LinqToDB.Mapping.Table(Name = "Posts")] 7 | public class Post 8 | { 9 | [LinqToDB.Mapping.PrimaryKey, LinqToDB.Mapping.Identity] 10 | public int Id { get; set; } 11 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 12 | public string Text { get; set; } 13 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.NotNull] 14 | public DateTime CreationDate { get; set; } 15 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.NotNull] 16 | public DateTime LastChangeDate { get; set; } 17 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 18 | public int? Counter1 { get; set; } 19 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 20 | public int? Counter2 { get; set; } 21 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 22 | public int? Counter3 { get; set; } 23 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 24 | public int? Counter4 { get; set; } 25 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 26 | public int? Counter5 { get; set; } 27 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 28 | public int? Counter6 { get; set; } 29 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 30 | public int? Counter7 { get; set; } 31 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 32 | public int? Counter8 { get; set; } 33 | [LinqToDB.Mapping.Column, LinqToDB.Mapping.Nullable] 34 | public int? Counter9 { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/SqlDataReaderHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Data.SqlClient; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace Dapper.Tests.Performance 6 | { 7 | public static class SqlDataReaderHelper 8 | { 9 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 10 | public static string GetNullableString(this SqlDataReader reader, int index) 11 | { 12 | object tmp = reader.GetValue(index); 13 | if (tmp != DBNull.Value) 14 | { 15 | return (string)tmp; 16 | } 17 | return null; 18 | } 19 | 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public static T? GetNullableValue(this SqlDataReader reader, int index) where T : struct 22 | { 23 | object tmp = reader.GetValue(index); 24 | if (tmp != DBNull.Value) 25 | { 26 | return (T)tmp; 27 | } 28 | return null; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/XPO/Post.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DevExpress.Xpo; 3 | 4 | namespace Dapper.Tests.Performance.Xpo 5 | { 6 | [Persistent("Posts")] 7 | public class Post : XPLiteObject 8 | { 9 | [Key(false)] 10 | public int Id { get; set; } 11 | public string Text { get; set; } 12 | public DateTime CreationDate { get; set; } 13 | public DateTime LastChangeDate { get; set; } 14 | public int? Counter1 { get; set; } 15 | public int? Counter2 { get; set; } 16 | public int? Counter3 { get; set; } 17 | public int? Counter4 { get; set; } 18 | public int? Counter5 { get; set; } 19 | public int? Counter6 { get; set; } 20 | public int? Counter7 { get; set; } 21 | public int? Counter8 { get; set; } 22 | public int? Counter9 { get; set; } 23 | public Post(Session session) : base(session) { } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /benchmarks/Dapper.Tests.Performance/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /benchmarks/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | false 6 | false 7 | false 8 | $(DefineConstants);WINDOWS 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /build.cmd: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0build.ps1' %*; exit $LASTEXITCODE" -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(PositionalBinding=$false)] 2 | param( 3 | [bool] $CreatePackages, 4 | [bool] $RunTests = $true, 5 | [string] $PullRequestNumber 6 | ) 7 | 8 | Write-Host "Run Parameters:" -ForegroundColor Cyan 9 | Write-Host " CreatePackages: $CreatePackages" 10 | Write-Host " RunTests: $RunTests" 11 | Write-Host " dotnet --version:" (dotnet --version) 12 | 13 | $packageOutputFolder = "$PSScriptRoot\.nupkgs" 14 | 15 | if ($PullRequestNumber) { 16 | Write-Host "Building for a pull request (#$PullRequestNumber), skipping packaging." -ForegroundColor Yellow 17 | $CreatePackages = $false 18 | } 19 | 20 | Write-Host "Building all projects (Build.csproj traversal)..." -ForegroundColor "Magenta" 21 | dotnet build ".\Build.csproj" -c Release /p:CI=true 22 | Write-Host "Done building." -ForegroundColor "Green" 23 | 24 | if ($RunTests) { 25 | Write-Host "Running tests: Build.csproj" -ForegroundColor "Magenta" 26 | dotnet test ".\Build.csproj" -c Release --no-build -p:TestTfmsInParallel=false 27 | if ($LastExitCode -ne 0) { 28 | Write-Host "Error with tests, aborting build." -Foreground "Red" 29 | Exit 1 30 | } 31 | Write-Host "Tests passed!" -ForegroundColor "Green" 32 | } 33 | 34 | if ($CreatePackages) { 35 | New-Item -ItemType Directory -Path $packageOutputFolder -Force | Out-Null 36 | Write-Host "Clearing existing $packageOutputFolder..." -NoNewline 37 | Get-ChildItem $packageOutputFolder | Remove-Item 38 | Write-Host "done." -ForegroundColor "Green" 39 | 40 | Write-Host "Building all packages" -ForegroundColor "Green" 41 | dotnet pack ".\Build.csproj" --no-build -c Release /p:PackageOutputPath=$packageOutputFolder /p:CI=true 42 | } 43 | Write-Host "Build Complete." -ForegroundColor "Green" 44 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /docs/dapper-sponsor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DapperLib/Dapper/00b1023f292c436eb9830b3383fde68e177a13bf/docs/dapper-sponsor.png -------------------------------------------------------------------------------- /docs/dapperplus.md: -------------------------------------------------------------------------------- 1 | # Dapper and Dapper Plus 2 | 3 | Dapper is the micro-ORM developed initially by Stack Overflow and now maintained independently, that offers simple, high performance 4 | access to the ADO.NET API. 5 | 6 | Dapper Plus is a separate tool by ZZZ Projects, which builds on the path set by Dapper, offering features like bulk operations, 7 | and a range of [documentation for Dapper](https://www.learndapper.com/). 8 | 9 | From 2024, Dapper Plus is now a major sponsor of Dapper, helping to secure ongoing quality development and support of the Dapper platform. 10 | This sponsorship does not impact the ownership, license, or any other particulars of how Dapper operates. The core Dapper libraries continue 11 | to be freely available and fully open source. 12 | 13 | Dapper Plus logo -------------------------------------------------------------------------------- /docs/dapperplus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DapperLib/Dapper/00b1023f292c436eb9830b3383fde68e177a13bf/docs/dapperplus.png -------------------------------------------------------------------------------- /docs/docs.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # Dapper 2 | 3 | Dapper is a simple micro-ORM used to simplify working with ADO.NET; if you like SQL but dislike the boilerplate of ADO.NET: Dapper is for you! 4 | 5 | As a simple example: 6 | 7 | ``` c# 8 | string region = ... 9 | var customers = connection.Query( 10 | "select * from Customers where Region = @region", // SQL 11 | new { region } // parameters 12 | ).AsList(); 13 | ``` 14 | 15 | But all the execute/single-row/scalar/async/etc functionality you would expect: is there as extension methods on your `DbConnection`. 16 | 17 | See [GitHub](https://github.com/DapperLib/Dapper) for more information and examples. 18 | 19 | Sponsors 20 | -------- 21 | 22 | Dapper was originally developed for and by Stack Overflow, but is F/OSS. Sponsorship is welcome and invited - see the sponsor link at the top of the page. 23 | A huge thanks to everyone (individuals or organisations) who have sponsored Dapper, but a massive thanks in particular to: 24 | 25 | - [Dapper Plus](https://dapper-plus.net/) is a major sponsor and is proud to contribute to the development of Dapper ([read more](https://dapperlib.github.io/Dapper/dapperplus)) 26 | - [AWS](https://github.com/aws) who sponsored Dapper from Oct 2023 via the [.NET on AWS Open Source Software Fund](https://github.com/aws/dotnet-foss) 27 | 28 | [![Dapper Plus logo](https://raw.githubusercontent.com/DapperLib/Dapper/main/docs/dapper-sponsor.png)](https://dapper-plus.net/) 29 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.101", 4 | "rollForward": "latestMajor" 5 | } 6 | } -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /signatures/version1/cla.json: -------------------------------------------------------------------------------- 1 | { 2 | "signedContributors": [] 3 | } -------------------------------------------------------------------------------- /tests/Dapper.Tests/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Dapper.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Dapper.Tests 4 | Dapper Core Test Suite 5 | net481;net8.0;net9.0 6 | $(DefineConstants);MSSQLCLIENT 7 | $(NoWarn);IDE0017;IDE0034;IDE0037;IDE0039;IDE0042;IDE0044;IDE0051;IDE0052;IDE0059;IDE0060;IDE0063;IDE1006;xUnit1004;CA1806;CA1816;CA1822;CA1825;CA2208;CA1861 8 | enable 9 | true 10 | 11 | 12 | 13 | $(DefineConstants);ENTITY_FRAMEWORK;LINQ2SQL;OLEDB 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | PreserveNewest 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/DateTimeOnlyTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Xunit; 4 | 5 | #if NET6_0_OR_GREATER 6 | namespace Dapper.Tests; 7 | 8 | /* we do **NOT** expect this to work against System.Data 9 | [Collection("DateTimeOnlyTests")] 10 | public sealed class SystemSqlClientDateTimeOnlyTests : DateTimeOnlyTests { } 11 | */ 12 | #if MSSQLCLIENT && DATEONLY 13 | [Collection("DateTimeOnlyTests")] 14 | public sealed class MicrosoftSqlClientDateTimeOnlyTests : DateTimeOnlyTests { } 15 | #endif 16 | public abstract class DateTimeOnlyTests : TestBase where TProvider : DatabaseProvider 17 | { 18 | public class HazDateTimeOnly 19 | { 20 | public string Name { get; set; } = ""; 21 | public DateOnly Date { get; set; } 22 | public TimeOnly Time { get; set; } 23 | public DateOnly? NDate { get; set; } 24 | public TimeOnly? NTime { get; set; } 25 | } 26 | 27 | [Fact] 28 | public void TypedInOut() 29 | { 30 | var now = DateTime.Now; 31 | var args = new HazDateTimeOnly 32 | { 33 | Name = nameof(TypedInOut), 34 | Date = DateOnly.FromDateTime(now), 35 | Time = TimeOnly.FromDateTime(now), 36 | NDate = DateOnly.FromDateTime(now), 37 | NTime = TimeOnly.FromDateTime(now), 38 | }; 39 | var row = connection.QuerySingle("select @name as [Name], @date as [Date], @time as [Time], @ndate as [NDate], @ntime as [NTime]", args); 40 | Assert.Equal(args.Name, row.Name); 41 | Assert.Equal(args.Date, row.Date); 42 | Assert.Equal(args.Time, row.Time); 43 | Assert.Equal(args.NDate, row.NDate); 44 | Assert.Equal(args.NTime, row.NTime); 45 | } 46 | 47 | [Fact] 48 | public async Task TypedInOutAsync() 49 | { 50 | var now = DateTime.Now; 51 | var args = new HazDateTimeOnly 52 | { 53 | Name = nameof(TypedInOutAsync), 54 | Date = DateOnly.FromDateTime(now), 55 | Time = TimeOnly.FromDateTime(now), 56 | NDate = DateOnly.FromDateTime(now), 57 | NTime = TimeOnly.FromDateTime(now), 58 | }; 59 | var row = await connection.QuerySingleAsync("select @name as [Name], @date as [Date], @time as [Time], @ndate as [NDate], @ntime as [NTime]", args); 60 | Assert.Equal(args.Name, row.Name); 61 | Assert.Equal(args.Date, row.Date); 62 | Assert.Equal(args.Time, row.Time); 63 | Assert.Equal(args.NDate, row.NDate); 64 | Assert.Equal(args.NTime, row.NTime); 65 | } 66 | 67 | [Fact] 68 | public void UntypedInOut() 69 | { 70 | var now = DateTime.Now; 71 | var args = new DynamicParameters(); 72 | var name = nameof(UntypedInOut); 73 | var date = DateOnly.FromDateTime(now); 74 | var time = TimeOnly.FromDateTime(now); 75 | args.Add("name", name); 76 | args.Add("date", date); 77 | args.Add("time", time); 78 | var row = connection.QuerySingle("select @name as [Name], @date as [Date], @time as [Time]", args); 79 | Assert.Equal(name, (string)row.Name); 80 | // untyped, observation is that these come back as DateTime and TimeSpan 81 | Assert.Equal(date, DateOnly.FromDateTime((DateTime)row.Date)); 82 | Assert.Equal(time, TimeOnly.FromTimeSpan((TimeSpan)row.Time)); 83 | } 84 | } 85 | #endif 86 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Helpers/Common.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Data.Common; 4 | using Xunit; 5 | 6 | namespace Dapper.Tests 7 | { 8 | public static class Common 9 | { 10 | public static Type GetSomeType() => typeof(SomeType); 11 | 12 | public static void DapperEnumValue(IDbConnection connection) 13 | { 14 | // test passing as AsEnum, reading as int 15 | var v = (AnEnum)connection.QuerySingle("select @v, @y, @z", new { v = AnEnum.B, y = (AnEnum?)AnEnum.B, z = (AnEnum?)null }); 16 | Assert.Equal(AnEnum.B, v); 17 | 18 | var args = new DynamicParameters(); 19 | args.Add("v", AnEnum.B); 20 | args.Add("y", AnEnum.B); 21 | args.Add("z", null); 22 | v = (AnEnum)connection.QuerySingle("select @v, @y, @z", args); 23 | Assert.Equal(AnEnum.B, v); 24 | 25 | // test passing as int, reading as AnEnum 26 | var k = (int)connection.QuerySingle("select @v, @y, @z", new { v = (int)AnEnum.B, y = (int?)(int)AnEnum.B, z = (int?)null }); 27 | Assert.Equal((int)AnEnum.B, k); 28 | 29 | args = new DynamicParameters(); 30 | args.Add("v", (int)AnEnum.B); 31 | args.Add("y", (int)AnEnum.B); 32 | args.Add("z", null); 33 | k = (int)connection.QuerySingle("select @v, @y, @z", args); 34 | Assert.Equal((int)AnEnum.B, k); 35 | } 36 | 37 | public static void TestDateTime(DbConnection connection) 38 | { 39 | DateTime? now = DateTime.UtcNow; 40 | try { connection.Execute("DROP TABLE Persons"); } catch { /* don't care */ } 41 | connection.Execute("CREATE TABLE Persons (id int not null, dob datetime null)"); 42 | connection.Execute("INSERT Persons (id, dob) values (@id, @dob)", 43 | new { id = 7, dob = (DateTime?)null }); 44 | connection.Execute("INSERT Persons (id, dob) values (@id, @dob)", 45 | new { id = 42, dob = now }); 46 | 47 | var row = connection.QueryFirstOrDefault( 48 | "SELECT id, dob, dob as dob2 FROM Persons WHERE id=@id", new { id = 7 }); 49 | Assert.NotNull(row); 50 | Assert.Equal(7, row.Id); 51 | Assert.Null(row.DoB); 52 | Assert.Null(row.DoB2); 53 | 54 | row = connection.QueryFirstOrDefault( 55 | "SELECT id, dob FROM Persons WHERE id=@id", new { id = 42 }); 56 | Assert.NotNull(row); 57 | Assert.Equal(42, row.Id); 58 | row.DoB.Equals(now); 59 | row.DoB2.Equals(now); 60 | } 61 | 62 | private class NullableDatePerson 63 | { 64 | public int Id { get; set; } 65 | public DateTime? DoB { get; set; } 66 | public DateTime? DoB2 { get; set; } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Helpers/IsExternalInit.cs: -------------------------------------------------------------------------------- 1 | namespace System.Runtime.CompilerServices; 2 | 3 | #if !NET5_0_OR_GREATER 4 | internal static class IsExternalInit 5 | { 6 | } 7 | #endif 8 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Helpers/SqlServerTypesLoader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.InteropServices; 4 | 5 | namespace Dapper.Tests 6 | { 7 | /// 8 | /// Utility methods related to CLR Types for SQL Server 9 | /// 10 | internal static class SqlServerTypesLoader 11 | { 12 | private static readonly object _nativeLoadLock = new object(); 13 | private static bool _nativeAssembliesLoaded; 14 | 15 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 16 | private static extern IntPtr LoadLibrary(string libname); 17 | 18 | /// 19 | /// Loads the required native assemblies for the current architecture (x86 or x64) 20 | /// 21 | /// 22 | /// Root path of the current application. Use Server.MapPath(".") for ASP.NET applications 23 | /// and AppDomain.CurrentDomain.BaseDirectory for desktop applications. 24 | /// 25 | public static void LoadNativeAssemblies(string rootApplicationPath) 26 | { 27 | if (_nativeAssembliesLoaded) 28 | return; 29 | lock (_nativeLoadLock) 30 | { 31 | if (!_nativeAssembliesLoaded) 32 | { 33 | var nativeBinaryPath = IntPtr.Size > 4 34 | ? Path.Combine(rootApplicationPath, @"x64\") 35 | : Path.Combine(rootApplicationPath, @"x86\"); 36 | Console.Write("(from: " + nativeBinaryPath + ")..."); 37 | LoadNativeAssembly(nativeBinaryPath, "msvcr120.dll"); 38 | LoadNativeAssembly(nativeBinaryPath, "SqlServerSpatial140.dll"); 39 | _nativeAssembliesLoaded = true; 40 | } 41 | } 42 | } 43 | 44 | private static void LoadNativeAssembly(string nativeBinaryPath, string assemblyName) 45 | { 46 | var path = Path.Combine(nativeBinaryPath, assemblyName); 47 | var ptr = LoadLibrary(path); 48 | if (ptr == IntPtr.Zero) 49 | { 50 | throw new Exception(string.Format( 51 | "Error loading {0} (ErrorCode: {1})", 52 | assemblyName, 53 | Marshal.GetLastWin32Error())); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Helpers/TransactedConnection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | 4 | namespace Dapper.Tests 5 | { 6 | public class TransactedConnection : IDbConnection 7 | { 8 | private readonly IDbConnection _conn; 9 | private readonly IDbTransaction _tran; 10 | 11 | public TransactedConnection(IDbConnection conn, IDbTransaction tran) 12 | { 13 | _conn = conn; 14 | _tran = tran; 15 | } 16 | 17 | public string ConnectionString 18 | { 19 | get { return _conn?.ConnectionString ?? ""; } 20 | #pragma warning disable CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). 21 | set { _conn.ConnectionString = value; } 22 | #pragma warning restore CS8767 // Nullability of reference types in type of parameter doesn't match implicitly implemented member (possibly because of nullability attributes). 23 | } 24 | 25 | public int ConnectionTimeout => _conn.ConnectionTimeout; 26 | public string Database => _conn.Database; 27 | public ConnectionState State => _conn.State; 28 | 29 | public IDbTransaction BeginTransaction(IsolationLevel il) 30 | { 31 | throw new NotImplementedException(); 32 | } 33 | 34 | public IDbTransaction BeginTransaction() => _tran; 35 | 36 | public void ChangeDatabase(string databaseName) => _conn.ChangeDatabase(databaseName); 37 | 38 | public void Close() => _conn.Close(); 39 | 40 | public IDbCommand CreateCommand() 41 | { 42 | // The command inherits the "current" transaction. 43 | var command = _conn.CreateCommand(); 44 | command.Transaction = _tran; 45 | return command; 46 | } 47 | 48 | public void Dispose() => _conn.Dispose(); 49 | 50 | public void Open() => _conn.Open(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/NullTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | using System.Linq; 3 | namespace Dapper.Tests 4 | { 5 | [Collection(NonParallelDefinition.Name)] 6 | public sealed class SystemSqlClientNullTests : NullTests { } 7 | #if MSSQLCLIENT 8 | [Collection(NonParallelDefinition.Name)] 9 | public sealed class MicrosoftSqlClientNullTests : NullTests { } 10 | #endif 11 | 12 | public abstract class NullTests : TestBase where TProvider : DatabaseProvider 13 | { 14 | [Fact] 15 | public void TestNullableDefault() 16 | { 17 | TestNullable(false); 18 | } 19 | 20 | [Fact] 21 | public void TestNullableApplyNulls() 22 | { 23 | TestNullable(true); 24 | } 25 | 26 | private void TestNullable(bool applyNulls) 27 | { 28 | bool oldSetting = SqlMapper.Settings.ApplyNullValues; 29 | try 30 | { 31 | SqlMapper.Settings.ApplyNullValues = applyNulls; 32 | SqlMapper.PurgeQueryCache(); 33 | 34 | var data = connection.Query(@" 35 | declare @data table(Id int not null, A int null, B int null, C varchar(20), D int null, E int null) 36 | insert @data (Id, A, B, C, D, E) values 37 | (1,null,null,null,null,null), 38 | (2,42,42,'abc',2,2) 39 | select * from @data").ToDictionary(_ => _.Id); 40 | 41 | var obj = data[2]; 42 | 43 | Assert.Equal(2, obj.Id); 44 | Assert.Equal(42, obj.A); 45 | Assert.Equal(42, obj.B); 46 | Assert.Equal("abc", obj.C); 47 | Assert.Equal(AnEnum.A, obj.D); 48 | Assert.Equal(AnEnum.A, obj.E); 49 | 50 | obj = data[1]; 51 | Assert.Equal(1, obj.Id); 52 | if (applyNulls) 53 | { 54 | Assert.Equal(2, obj.A); // cannot be null 55 | Assert.Null(obj.B); 56 | Assert.Null(obj.C); 57 | Assert.Equal(AnEnum.B, obj.D); 58 | Assert.Null(obj.E); 59 | } 60 | else 61 | { 62 | Assert.Equal(2, obj.A); 63 | Assert.Equal(2, obj.B); 64 | Assert.Equal("def", obj.C); 65 | Assert.Equal(AnEnum.B, obj.D); 66 | Assert.Equal(AnEnum.B, obj.E); 67 | } 68 | } 69 | finally 70 | { 71 | SqlMapper.Settings.ApplyNullValues = oldSetting; 72 | } 73 | } 74 | 75 | private class NullTestClass 76 | { 77 | public int Id { get; set; } 78 | public int A { get; set; } 79 | public int? B { get; set; } 80 | public string C { get; set; } 81 | public AnEnum D { get; set; } 82 | public AnEnum? E { get; set; } 83 | 84 | public NullTestClass() 85 | { 86 | A = 2; 87 | B = 2; 88 | C = "def"; 89 | D = AnEnum.B; 90 | E = AnEnum.B; 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Providers/DuckDBTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Common; 3 | using DuckDB.NET.Data; 4 | using Xunit; 5 | 6 | namespace Dapper.Tests 7 | { 8 | public class DuckDBProvider : DatabaseProvider 9 | { 10 | public override DbProviderFactory Factory => DuckDBClientFactory.Instance; 11 | public override string GetConnectionString() => "Data Source=:memory:"; 12 | } 13 | 14 | public abstract class DuckDBTypeTestBase : TestBase 15 | { 16 | protected DuckDBConnection GetDuckDBConnection(bool open = true) 17 | => (DuckDBConnection)(open ? Provider.GetOpenConnection() : Provider.GetClosedConnection()); 18 | 19 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 20 | public class FactDuckDBAttribute : FactAttribute 21 | { 22 | public override string? Skip 23 | { 24 | get { return unavailable ?? base.Skip; } 25 | set { base.Skip = value; } 26 | } 27 | 28 | private static readonly string? unavailable; 29 | 30 | static FactDuckDBAttribute() 31 | { 32 | try 33 | { 34 | using var _ = DatabaseProvider.Instance.GetOpenConnection(); 35 | } 36 | catch (Exception ex) 37 | { 38 | unavailable = $"DuckDB is unavailable: {ex.Message}"; 39 | } 40 | } 41 | } 42 | } 43 | 44 | public class DuckDBTests : DuckDBTypeTestBase 45 | { 46 | [FactDuckDB] 47 | public void DuckDBNamedParameter() 48 | { 49 | using var connection = GetDuckDBConnection(); 50 | 51 | var result = connection.QueryFirst("Select $foo", new {foo = 42}); 52 | Assert.Equal(42, result); 53 | } 54 | 55 | [FactDuckDB] 56 | public void DuckDBPositionalParameter() 57 | { 58 | using var connection = GetDuckDBConnection(); 59 | 60 | var dp = new DynamicParameters(); 61 | dp.Add("?", 42); 62 | 63 | var result = connection.QueryFirst("Select ?", dp); 64 | Assert.Equal(42, result); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Providers/EntityFrameworkTests.cs: -------------------------------------------------------------------------------- 1 | #if ENTITY_FRAMEWORK 2 | using System; 3 | using System.Data.Entity.Spatial; 4 | using System.Linq; 5 | using Xunit; 6 | 7 | namespace Dapper.Tests.Providers 8 | { 9 | public sealed class SystemSqlClientEntityFrameworkTests : EntityFrameworkTests { } 10 | #if MSSQLCLIENT 11 | public sealed class MicrosoftSqlClientEntityFrameworkTests : EntityFrameworkTests { } 12 | #endif 13 | 14 | [Collection("TypeHandlerTests")] 15 | public abstract class EntityFrameworkTests : TestBase where TProvider : DatabaseProvider 16 | { 17 | public EntityFrameworkTests() 18 | { 19 | EntityFramework.Handlers.Register(); 20 | } 21 | 22 | [Fact] 23 | public void Issue570_DbGeo_HasValues() 24 | { 25 | SkipIfMsDataClient(); 26 | 27 | EntityFramework.Handlers.Register(); 28 | const string redmond = "POINT (-122.1215 47.6740)"; 29 | DbGeography point = DbGeography.PointFromText(redmond, DbGeography.DefaultCoordinateSystemId); 30 | DbGeography orig = point.Buffer(20); 31 | 32 | var fromDb = connection.QuerySingle("declare @geos table(geo geography); insert @geos(geo) values(@val); select * from @geos", 33 | new { val = orig }); 34 | 35 | Assert.NotNull(fromDb.Area); 36 | Assert.Equal(orig.Area, fromDb.Area); 37 | } 38 | 39 | [Fact] 40 | public void Issue22_ExecuteScalar_EntityFramework() 41 | { 42 | SkipIfMsDataClient(); 43 | 44 | var geo = DbGeography.LineFromText("LINESTRING(-122.360 47.656, -122.343 47.656 )", 4326); 45 | var geo2 = connection.ExecuteScalar("select @geo", new { geo }); 46 | Assert.NotNull(geo2); 47 | } 48 | 49 | [Fact] 50 | public void TestGeometryParsingRetainsSrid() 51 | { 52 | const int srid = 27700; 53 | var s = $@"DECLARE @EdinburghPoint GEOMETRY = geometry::STPointFromText('POINT(258647 665289)', {srid}); 54 | SELECT @EdinburghPoint"; 55 | var edinPoint = connection.Query(s).Single(); 56 | Assert.NotNull(edinPoint); 57 | Assert.Equal(srid, edinPoint.CoordinateSystemId); 58 | } 59 | 60 | [Fact] 61 | public void TestGeographyParsingRetainsSrid() 62 | { 63 | const int srid = 4324; 64 | var s = $@"DECLARE @EdinburghPoint GEOGRAPHY = geography::STPointFromText('POINT(-3.19 55.95)', {srid}); 65 | SELECT @EdinburghPoint"; 66 | var edinPoint = connection.Query(s).Single(); 67 | Assert.NotNull(edinPoint); 68 | Assert.Equal(srid, edinPoint.CoordinateSystemId); 69 | } 70 | 71 | } 72 | } 73 | #endif 74 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Providers/FirebirdTests.cs: -------------------------------------------------------------------------------- 1 | using FirebirdSql.Data.FirebirdClient; 2 | using System.Data; 3 | using System.Data.Common; 4 | using System.Linq; 5 | using Xunit; 6 | 7 | namespace Dapper.Tests.Providers 8 | { 9 | /// 10 | /// If Docker Desktop is installed, run the following command to start a container suitable for the tests. 11 | /// 12 | /// docker run -d -p 3050:3050 --name Dapper.Tests.Firebird -e FIREBIRD_DATABASE=database -e ISC_PASSWORD=masterkey jacobalberty/firebird 13 | /// 14 | /// 15 | public class FirebirdProvider : DatabaseProvider 16 | { 17 | public override DbProviderFactory Factory => FirebirdClientFactory.Instance; 18 | public override string GetConnectionString() => "initial catalog=localhost:database;user id=SYSDBA;password=masterkey"; 19 | } 20 | public class FirebirdTests : TestBase 21 | { 22 | private FbConnection GetOpenFirebirdConnection() => (FbConnection)Provider.GetOpenConnection(); 23 | 24 | [Fact(Skip = "Bug in Firebird; a PR to fix it has been submitted")] 25 | public void Issue178_Firebird() 26 | { 27 | using var connection = GetOpenFirebirdConnection(); 28 | 29 | const string sql = "select count(*) from Issue178"; 30 | try { connection.Execute("drop table Issue178"); } 31 | catch { /* don't care */ } 32 | connection.Execute("create table Issue178(id int not null)"); 33 | connection.Execute("insert into Issue178(id) values(42)"); 34 | // raw ADO.net 35 | using (var sqlCmd = new FbCommand(sql, connection)) 36 | using (var reader1 = sqlCmd.ExecuteReader()) 37 | { 38 | Assert.True(reader1.Read()); 39 | Assert.Equal(1, reader1.GetInt32(0)); 40 | Assert.False(reader1.Read()); 41 | Assert.False(reader1.NextResult()); 42 | } 43 | 44 | // dapper 45 | using (var reader2 = connection.ExecuteReader(sql)) 46 | { 47 | Assert.True(reader2.Read()); 48 | Assert.Equal(1, reader2.GetInt32(0)); 49 | Assert.False(reader2.Read()); 50 | Assert.False(reader2.NextResult()); 51 | } 52 | 53 | var count = connection.Query(sql).Single(); 54 | Assert.Equal(1, count); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Providers/Linq2SqlTests.cs: -------------------------------------------------------------------------------- 1 | #if LINQ2SQL 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Xunit; 8 | 9 | namespace Dapper.Tests 10 | { 11 | public sealed class SystemSqlClientLinq2SqlTests : Linq2SqlTests { } 12 | #if MSSQLCLIENT 13 | public sealed class MicrosoftSqlClientLinq2SqlTests : Linq2SqlTests { } 14 | #endif 15 | public abstract class Linq2SqlTests : TestBase where TProvider : DatabaseProvider 16 | { 17 | [Fact] 18 | public void TestLinqBinaryToClass() 19 | { 20 | byte[] orig = new byte[20]; 21 | new Random(123456).NextBytes(orig); 22 | var input = new System.Data.Linq.Binary(orig); 23 | 24 | var output = connection.Query("select @input as [Value]", new { input }).First().Value; 25 | 26 | Assert.Equal(orig, output?.ToArray()); 27 | } 28 | 29 | [Fact] 30 | public void TestLinqBinaryRaw() 31 | { 32 | byte[] orig = new byte[20]; 33 | new Random(123456).NextBytes(orig); 34 | var input = new System.Data.Linq.Binary(orig); 35 | 36 | var output = connection.Query("select @input as [Value]", new { input }).First(); 37 | 38 | Assert.Equal(orig, output.ToArray()); 39 | } 40 | 41 | private class WithBinary 42 | { 43 | public System.Data.Linq.Binary? Value { get; set; } 44 | } 45 | 46 | private class NoDefaultConstructorWithBinary 47 | { 48 | public System.Data.Linq.Binary Value { get; set; } 49 | public int Ynt { get; set; } 50 | public NoDefaultConstructorWithBinary(System.Data.Linq.Binary val) 51 | { 52 | Value = val; 53 | } 54 | } 55 | 56 | [Fact] 57 | public void TestNoDefaultConstructorBinary() 58 | { 59 | byte[] orig = new byte[20]; 60 | new Random(123456).NextBytes(orig); 61 | var input = new System.Data.Linq.Binary(orig); 62 | var output = connection.Query("select @input as val", new { input }).First().Value; 63 | Assert.Equal(orig, output.ToArray()); 64 | } 65 | } 66 | } 67 | #endif 68 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/Providers/SnowflakeTests.cs: -------------------------------------------------------------------------------- 1 | #if !NETFRAMEWORK // platform not supported exception 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using Snowflake.Data.Client; 6 | using Xunit; 7 | using Xunit.Abstractions; 8 | 9 | namespace Dapper.Tests 10 | { 11 | public class SnowflakeTests 12 | { 13 | static readonly string? s_ConnectionString; 14 | static SnowflakeTests() 15 | { 16 | SqlMapper.Settings.UseIncrementalPseudoPositionalParameterNames = true; 17 | 18 | try 19 | { // this *probably* won't exist (TODO: can we get a test account?) 20 | s_ConnectionString = File.ReadAllText(@"c:\Code\SnowflakeConnectionString.txt").Trim(); 21 | } catch { } 22 | } 23 | 24 | public SnowflakeTests(ITestOutputHelper output) 25 | => Output = output; 26 | 27 | private ITestOutputHelper Output { get; } 28 | 29 | 30 | private static SnowflakeDbConnection GetConnection() 31 | { 32 | if (string.IsNullOrWhiteSpace(s_ConnectionString)) 33 | Skip.Inconclusive("no snowflake connection-string"); 34 | 35 | return new SnowflakeDbConnection 36 | { 37 | ConnectionString = s_ConnectionString 38 | }; 39 | } 40 | 41 | [Fact] 42 | public void Connect() 43 | { 44 | using var connection = GetConnection(); 45 | connection.Open(); 46 | } 47 | 48 | 49 | [Fact] 50 | public void BasicQuery() 51 | { 52 | 53 | using var connection = GetConnection(); 54 | var nations = connection.Query(@"SELECT * FROM NATION").AsList(); 55 | Assert.NotEmpty(nations); 56 | Output.WriteLine($"nations: {nations.Count}"); 57 | foreach (var nation in nations) 58 | { 59 | Output.WriteLine($"{nation.N_NATIONKEY}: {nation.N_NAME} (region: {nation.N_REGIONKEY}), {nation.N_COMMENT}"); 60 | } 61 | } 62 | 63 | [Fact] 64 | public void ParameterizedQuery() 65 | { 66 | using var connection = GetConnection(); 67 | const int region = 1; 68 | var nations = connection.Query(@"SELECT * FROM NATION WHERE N_REGIONKEY=?region?", new { region }).AsList(); 69 | Assert.NotEmpty(nations); 70 | Output.WriteLine($"nations: {nations.Count}"); 71 | foreach (var nation in nations) 72 | { 73 | Output.WriteLine($"{nation.N_NATIONKEY}: {nation.N_NAME} (region: {nation.N_REGIONKEY}), {nation.N_COMMENT}"); 74 | } 75 | } 76 | 77 | public class Nation 78 | { 79 | public int N_NATIONKEY { get; set; } 80 | public string? N_NAME{ get; set; } 81 | public int N_REGIONKEY { get; set; } 82 | public string? N_COMMENT { get; set; } 83 | } 84 | } 85 | } 86 | #endif 87 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Address.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class Address 4 | { 5 | public int AddressId { get; set; } 6 | public string? Name { get; set; } 7 | public int PersonId { get; set; } 8 | public Index? Index { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Bar1.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class Bar1 4 | { 5 | public int BarId; 6 | public string? Name { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Category.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class Category 4 | { 5 | public int Id { get; set; } 6 | public string? Name { get; set; } 7 | public string? Description { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Comment.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class Comment 4 | { 5 | public int Id { get; set; } 6 | public string? CommentData { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Dog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Dapper.Tests 4 | { 5 | public class Dog 6 | { 7 | public int? Age { get; set; } 8 | public Guid Id { get; set; } 9 | public string? Name { get; set; } 10 | public float? Weight { get; set; } 11 | 12 | public int IgnoredProperty => 1; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Enums.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | internal enum AnEnum 4 | { 5 | A = 2, 6 | B = 1 7 | } 8 | 9 | internal enum AnotherEnum : byte 10 | { 11 | A = 2, 12 | B = 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Foo1.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class Foo1 4 | { 5 | public int Id; 6 | public int BarId { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/HazNameId.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class HazNameId 4 | { 5 | public string? Name { get; set; } 6 | public int Id { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Index.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class Index 4 | { 5 | public string? Id { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Person.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class Person 4 | { 5 | public int PersonId { get; set; } 6 | public string? Name { get; set; } 7 | public string? Occupation { get; private set; } 8 | public int NumberOfLegs = 2; 9 | public Address? Address { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Post.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class Post 4 | { 5 | public int Id { get; set; } 6 | public User? Owner { get; set; } 7 | public string? Content { get; set; } 8 | public Comment? Comment { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/Product.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class Product 4 | { 5 | public int Id { get; set; } 6 | public string? Name { get; set; } 7 | public Category? Category { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/ReviewBoard.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class ReviewBoard 4 | { 5 | public int Id { get; set; } 6 | public string? Name { get; set; } 7 | public User? User1 { get; set; } 8 | public User? User2 { get; set; } 9 | public User? User3 { get; set; } 10 | public User? User4 { get; set; } 11 | public User? User5 { get; set; } 12 | public User? User6 { get; set; } 13 | public User? User7 { get; set; } 14 | public User? User8 { get; set; } 15 | public User? User9 { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/ShortEnum.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public enum ShortEnum : short 4 | { 5 | Zero = 0, 6 | One = 1, 7 | Two = 2, 8 | Three = 3, 9 | Four = 4, 10 | Five = 5, 11 | Six = 6 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/SomeType.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class SomeType 4 | { 5 | public int A { get; set; } 6 | public string? B { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SharedTypes/User.cs: -------------------------------------------------------------------------------- 1 | namespace Dapper.Tests 2 | { 3 | public class User 4 | { 5 | public int Id { get; set; } 6 | public string? Name { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/SqlBuilderTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Xunit; 4 | 5 | namespace Dapper.Tests 6 | { 7 | [Collection("SqlBuilderTests")] 8 | public sealed class SystemSqlClientSqlBuilderTests : SqlBuilderTests { } 9 | #if MSSQLCLIENT 10 | [Collection("SqlBuilderTests")] 11 | public sealed class MicrosoftSqlClientSqlBuilderTests : SqlBuilderTests { } 12 | #endif 13 | public abstract class SqlBuilderTests : TestBase where TProvider : DatabaseProvider 14 | { 15 | [Fact] 16 | public void TestSqlBuilderWithDapperQuery() 17 | { 18 | var sb = new SqlBuilder(); 19 | var template = sb.AddTemplate("SELECT /**select**/ FROM #Users /**where**/"); 20 | sb.Where("Age <= @Age", new { Age = 18 }) 21 | .Where("Country = @Country", new { Country = "USA" }) 22 | .Select("Name,Age,Country"); 23 | 24 | const string createSql = @" 25 | create table #Users (Name varchar(20),Age int,Country nvarchar(5)); 26 | insert #Users values('Sam',16,'USA'),('Tom',25,'UK'),('Henry',14,'UK')"; 27 | try 28 | { 29 | connection.Execute(createSql); 30 | 31 | var result = connection.Query(template.RawSql,template.Parameters).ToArray(); 32 | 33 | Assert.Equal("SELECT Name,Age,Country\n FROM #Users WHERE Age <= @Age AND Country = @Country\n", template.RawSql); 34 | 35 | Assert.Single(result); 36 | 37 | Assert.Equal(16, (int)result[0].Age); 38 | Assert.Equal("Sam", (string)result[0].Name); 39 | Assert.Equal("USA", (string)result[0].Country); 40 | } 41 | finally 42 | { 43 | connection.Execute("drop table #Users"); 44 | } 45 | } 46 | 47 | [Fact] 48 | public void TestSqlBuilderUpdateSet() 49 | { 50 | var id = 1; 51 | var vip = true; 52 | var updatetime = DateTime.Parse("2020/01/01"); 53 | 54 | var sb = new SqlBuilder() 55 | .Set("Vip = @vip", new { vip }) 56 | .Set("Updatetime = @updatetime", new { updatetime }) 57 | .Where("Id = @id", new { id }) 58 | ; 59 | var template = sb.AddTemplate("update #Users /**set**/ /**where**/"); 60 | 61 | const string createSql = @" 62 | create table #Users (Id int,Name varchar(20),Age int,Country nvarchar(5),Vip bit,Updatetime datetime); 63 | insert #Users (Id,Name,Age,Country) values(1,'Sam',16,'USA'),(2,'Tom',25,'UK'),(3,'Henry',14,'UK')"; 64 | try 65 | { 66 | connection.Execute(createSql); 67 | 68 | var effectCount = connection.Execute(template.RawSql, template.Parameters); 69 | 70 | var result = connection.QueryFirst("select * from #Users where Id = 1"); 71 | 72 | Assert.Equal("update #Users SET Vip = @vip , Updatetime = @updatetime\n WHERE Id = @id\n", template.RawSql); 73 | 74 | 75 | Assert.True((bool)result.Vip); 76 | Assert.Equal(updatetime, (DateTime)result.Updatetime); 77 | } 78 | finally 79 | { 80 | connection.Execute("drop table #Users"); 81 | } 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/TransactionTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | namespace Dapper.Tests 9 | { 10 | [Collection("TransactionTests")] 11 | public sealed class SystemSqlClientTransactionTests : TransactionTests { } 12 | #if MSSQLCLIENT 13 | [Collection("TransactionTests")] 14 | public sealed class MicrosoftSqlClientTransactionTests : TransactionTests { } 15 | #endif 16 | public abstract class TransactionTests : TestBase where TProvider : DatabaseProvider 17 | { 18 | [Fact] 19 | public void TestTransactionCommit() 20 | { 21 | try 22 | { 23 | connection.Execute("create table #TransactionTest ([ID] int, [Value] varchar(32));"); 24 | 25 | using (var transaction = connection.BeginTransaction()) 26 | { 27 | connection.Execute("insert into #TransactionTest ([ID], [Value]) values (1, 'ABC');", transaction: transaction); 28 | 29 | transaction.Commit(); 30 | } 31 | 32 | Assert.Equal(1, connection.Query("select count(*) from #TransactionTest;").Single()); 33 | } 34 | finally 35 | { 36 | connection.Execute("drop table #TransactionTest;"); 37 | } 38 | } 39 | 40 | [Fact] 41 | public void TestTransactionRollback() 42 | { 43 | connection.Execute("create table #TransactionTest ([ID] int, [Value] varchar(32));"); 44 | 45 | try 46 | { 47 | using (var transaction = connection.BeginTransaction()) 48 | { 49 | connection.Execute("insert into #TransactionTest ([ID], [Value]) values (1, 'ABC');", transaction: transaction); 50 | 51 | transaction.Rollback(); 52 | } 53 | 54 | Assert.Equal(0, connection.Query("select count(*) from #TransactionTest;").Single()); 55 | } 56 | finally 57 | { 58 | connection.Execute("drop table #TransactionTest;"); 59 | } 60 | } 61 | 62 | [Fact] 63 | public void TestCommandWithInheritedTransaction() 64 | { 65 | connection.Execute("create table #TransactionTest ([ID] int, [Value] varchar(32));"); 66 | 67 | try 68 | { 69 | using (var transaction = connection.BeginTransaction()) 70 | { 71 | var transactedConnection = new TransactedConnection(connection, transaction); 72 | 73 | transactedConnection.Execute("insert into #TransactionTest ([ID], [Value]) values (1, 'ABC');"); 74 | 75 | transaction.Rollback(); 76 | } 77 | 78 | Assert.Equal(0, connection.Query("select count(*) from #TransactionTest;").Single()); 79 | } 80 | finally 81 | { 82 | connection.Execute("drop table #TransactionTest;"); 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/XmlTests.cs: -------------------------------------------------------------------------------- 1 | using System.Xml; 2 | using System.Xml.Linq; 3 | using Xunit; 4 | 5 | namespace Dapper.Tests 6 | { 7 | [Collection("XmlTests")] 8 | public sealed class SystemSqlClientXmlTests : XmlTests { } 9 | #if MSSQLCLIENT 10 | [Collection("XmlTests")] 11 | public sealed class MicrosoftSqlClientXmlTests : XmlTests { } 12 | #endif 13 | public abstract class XmlTests : TestBase where TProvider : DatabaseProvider 14 | { 15 | [Fact] 16 | public void CommonXmlTypesSupported() 17 | { 18 | var xml = new XmlDocument(); 19 | xml.LoadXml(""); 20 | 21 | var foo = new Foo 22 | { 23 | A = xml, 24 | B = XDocument.Parse(""), 25 | C = XElement.Parse("") 26 | }; 27 | var bar = connection.QuerySingle("select @a as [A], @b as [B], @c as [C]", new { a = foo.A, b = foo.B, c = foo.C }); 28 | Assert.Equal("abc", bar.A?.DocumentElement?.Name); 29 | Assert.Equal("def", bar.B?.Root?.Name.LocalName); 30 | Assert.Equal("ghi", bar.C?.Name.LocalName); 31 | } 32 | 33 | public class Foo 34 | { 35 | public XmlDocument? A { get; set; } 36 | public XDocument? B { get; set; } 37 | public XElement? C { get; set; } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/Dapper.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", 3 | "shadowCopy": false 4 | } -------------------------------------------------------------------------------- /tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Library 5 | false 6 | false 7 | false 8 | false 9 | true 10 | 11 | Full 12 | $(DefineConstants);WINDOWS 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | 5 | -------------------------------------------------------------------------------- /tests/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | mysql: 4 | image: mysql:8 5 | container_name: mysql 6 | ports: 7 | - 3306:3306 8 | environment: 9 | MYSQL_ROOT_PASSWORD: root 10 | MYSQL_DATABASE: test 11 | postgres: 12 | image: postgres:alpine 13 | container_name: postgres 14 | ports: 15 | - 5432:5432 16 | environment: 17 | POSTGRES_USER: postgres 18 | POSTGRES_PASSWORD: postgres 19 | POSTGRES_DB: test 20 | sqlserver: 21 | image: mcr.microsoft.com/mssql/server:2019-latest 22 | container_name: sql-server-db 23 | ports: 24 | - 1433:1433 25 | environment: 26 | ACCEPT_EULA: Y 27 | SA_PASSWORD: "Password." 28 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.1", 3 | "assemblyVersion": "2.0.0.0", 4 | "publicReleaseRefSpec": [ 5 | "^refs/heads/main$", 6 | "^refs/tags/v\\d+\\.\\d+" 7 | ], 8 | "nugetPackageVersion": { 9 | "semVer": 2 10 | }, 11 | "cloudBuild": { 12 | "buildNumber": { 13 | "enabled": true, 14 | "setVersionVariables": true 15 | } 16 | } 17 | } --------------------------------------------------------------------------------