From e97a91935243299d45bece0c401103abadf12a1b Mon Sep 17 00:00:00 2001 From: Jesper Noordsij <45041769+jnoordsij@users.noreply.github.com> Date: Tue, 8 Apr 2025 12:01:52 +0200 Subject: [PATCH 01/13] Fix and clarify OrWhere caveats in SqlBuilder docs (#2149) * Fix and clarify OrWhere caveats in SqlBuilder docs * Add example with OrWhere call first --- Dapper.SqlBuilder/Readme.md | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/Dapper.SqlBuilder/Readme.md b/Dapper.SqlBuilder/Readme.md index ea69d9b80..5a0968f9f 100644 --- a/Dapper.SqlBuilder/Readme.md +++ b/Dapper.SqlBuilder/Readme.md @@ -85,10 +85,16 @@ var count = conn.ExecuteScalar(countTemplate.RawSql, countTemplate.Paramete Limitations and caveats -------- -OrWhere use `and` not `or` to concat sql problem +### Combining the Where and OrWhere methods -[Issue 647](https://github.com/DapperLib/Dapper/issues/647) +The OrWhere method currently groups all `and` and `or` clauses by type, +then join the groups with `and` or `or` depending on the first call. +This may result in possibly unexpected outcomes. +See also [issue 647](https://github.com/DapperLib/Dapper/issues/647). +#### Example Where first + +When providing the following clauses ```csharp sql.Where("a = @a1"); sql.OrWhere("b = @b1"); @@ -97,11 +103,26 @@ sql.OrWhere("b = @b2"); ``` SqlBuilder will generate sql -```sql= -a = @a1 AND b = @b1 AND a = @a2 AND b = @b2 +```sql +a = @a1 AND a = @a2 AND ( b = @b1 OR b = @b2 ) ``` -not +and not say ```sql a = @a1 OR b = @b1 AND a = @a2 OR b = @b2 ``` + +#### Example OrWhere first + +When providing the following clauses +```csharp +sql.OrWhere("b = @b1"); +sql.Where("a = @a1"); +sql.OrWhere("b = @b2"); +sql.Where("a = @a2"); +``` + +SqlBuilder will generate sql +```sql +a = @a1 OR a = @a2 OR ( b = @b1 OR b = @b2 ) +``` From d994b6d93265f1318a064f5f3ebbcb1f3aaf53cf Mon Sep 17 00:00:00 2001 From: ri-rgb <70099947+ri-rgb@users.noreply.github.com> Date: Tue, 8 Apr 2025 11:07:45 +0100 Subject: [PATCH 02/13] OutputExpression wasn't working for methods that use QueryRowAsync (#2156) Added command.OnCompleted() to QueryRowAsync Co-authored-by: Rich --- Dapper/SqlMapper.Async.cs | 1 + tests/Dapper.Tests/AsyncTests.cs | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/Dapper/SqlMapper.Async.cs b/Dapper/SqlMapper.Async.cs index fb7ce448c..eade08cb2 100644 --- a/Dapper/SqlMapper.Async.cs +++ b/Dapper/SqlMapper.Async.cs @@ -503,6 +503,7 @@ private static async Task QueryRowAsync(this IDbConnection cnn, Row row, T ThrowZeroRows(row); } while (await reader.NextResultAsync(cancel).ConfigureAwait(false)) { /* ignore result sets after the first */ } + command.OnCompleted(); return result; } finally diff --git a/tests/Dapper.Tests/AsyncTests.cs b/tests/Dapper.Tests/AsyncTests.cs index ec83dc2d9..9c3ec4721 100644 --- a/tests/Dapper.Tests/AsyncTests.cs +++ b/tests/Dapper.Tests/AsyncTests.cs @@ -667,6 +667,34 @@ public async Task TestSupportForDynamicParametersOutputExpressions_Query_Default Assert.Equal(42, result); } + [Fact] + public async Task TestSupportForDynamicParametersOutputExpressions_QueryFirst() + { + var bob = new Person { Name = "bob", PersonId = 1, Address = new Address { PersonId = 2 } }; + + var p = new DynamicParameters(bob); + p.Output(bob, b => b.PersonId); + p.Output(bob, b => b.Occupation); + p.Output(bob, b => b.NumberOfLegs); + p.Output(bob, b => b.Address!.Name); + p.Output(bob, b => b.Address!.PersonId); + + var result = (await connection.QueryFirstAsync(@" +SET @Occupation = 'grillmaster' +SET @PersonId = @PersonId + 1 +SET @NumberOfLegs = @NumberOfLegs - 1 +SET @AddressName = 'bobs burgers' +SET @AddressPersonId = @PersonId +select 42", p).ConfigureAwait(false)); + + Assert.Equal("grillmaster", bob.Occupation); + Assert.Equal(2, bob.PersonId); + Assert.Equal(1, bob.NumberOfLegs); + Assert.Equal("bobs burgers", bob.Address.Name); + Assert.Equal(2, bob.Address.PersonId); + Assert.Equal(42, result); + } + [Fact] public async Task TestSupportForDynamicParametersOutputExpressions_Query_BufferedAsync() { From 5e6a6eb82f623f52265f93d7243e4ccb7bff5b81 Mon Sep 17 00:00:00 2001 From: kabaome Date: Mon, 28 Apr 2025 03:34:35 +0900 Subject: [PATCH 03/13] CI: use preinstalled sdk (#2160) --- appveyor.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8c1e48d84..ae9d477bf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,9 +6,6 @@ skip_commits: files: - '**/*.md' -install: - - choco install dotnet-sdk --version 9.0.101 - environment: Appveyor: true # Postgres From 5c7143f2e3585d4708294a3b0530a134e18ace86 Mon Sep 17 00:00:00 2001 From: kabaome Date: Thu, 1 May 2025 04:31:40 +0900 Subject: [PATCH 04/13] CI: serialize DB-dependent tests (#2163) * CI: serialize DB-dependent tests * github workflows test --- .github/workflows/main.yml | 2 +- build.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 497e5a0bf..7a910196d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -47,7 +47,7 @@ jobs: - name: .NET Build run: dotnet build Build.csproj -c Release /p:CI=true - name: Dapper Tests - run: dotnet test tests/Dapper.Tests/Dapper.Tests.csproj -c Release --logger GitHubActions /p:CI=true + run: dotnet test tests/Dapper.Tests/Dapper.Tests.csproj -c Release --logger GitHubActions -p:CI=true -p:TestTfmsInParallel=false env: MySqlConnectionString: Server=localhost;Port=${{ job.services.mysql.ports[3306] }};Uid=root;Pwd=root;Database=test;Allow User Variables=true OLEDBConnectionString: Provider=SQLOLEDB;Server=tcp:localhost,${{ job.services.sqlserver.ports[1433] }};Database=tempdb;User Id=sa;Password=Password.; diff --git a/build.ps1 b/build.ps1 index f406c745f..59193ff75 100644 --- a/build.ps1 +++ b/build.ps1 @@ -22,8 +22,8 @@ dotnet build ".\Build.csproj" -c Release /p:CI=true Write-Host "Done building." -ForegroundColor "Green" if ($RunTests) { - Write-Host "Running tests: Build.csproj traversal (all frameworks)" -ForegroundColor "Magenta" - dotnet test ".\Build.csproj" -c Release --no-build + Write-Host "Running tests: Build.csproj" -ForegroundColor "Magenta" + dotnet test ".\Build.csproj" -c Release --no-build -p:TestTfmsInParallel=false if ($LastExitCode -ne 0) { Write-Host "Error with tests, aborting build." -Foreground "Red" Exit 1 From 00b1023f292c436eb9830b3383fde68e177a13bf Mon Sep 17 00:00:00 2001 From: mgravell Date: Sun, 1 Jun 2025 06:50:51 +0100 Subject: [PATCH 05/13] rev snowflake for clean build --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d72d03090..8787a7767 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -35,7 +35,7 @@ - + From 288730e69b05c32cac898d9b55ebea219ea8a2d1 Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Fri, 6 Mar 2026 07:10:01 +0000 Subject: [PATCH 06/13] TFM packaging for .NET 10 (#2195) --- .github/workflows/main.yml | 2 +- Dapper.StrongName/Dapper.StrongName.csproj | 2 +- Dapper/Dapper.csproj | 2 +- global.json | 2 +- tests/Dapper.Tests/Dapper.Tests.csproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7a910196d..3145873c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,7 +43,7 @@ jobs: - name: Setup dotnet uses: actions/setup-dotnet@v4 with: - dotnet-version: '9.0.x' + dotnet-version: '10.0.x' - name: .NET Build run: dotnet build Build.csproj -c Release /p:CI=true - name: Dapper Tests diff --git a/Dapper.StrongName/Dapper.StrongName.csproj b/Dapper.StrongName/Dapper.StrongName.csproj index f202f8f6c..2aae43d73 100644 --- a/Dapper.StrongName/Dapper.StrongName.csproj +++ b/Dapper.StrongName/Dapper.StrongName.csproj @@ -5,7 +5,7 @@ Dapper (Strong Named) A high performance Micro-ORM supporting SQL Server, MySQL, Sqlite, SqlCE, Firebird etc. Major Sponsor: Dapper Plus from ZZZ Projects. Sam Saffron;Marc Gravell;Nick Craver - net461;netstandard2.0;net8.0 + net461;netstandard2.0;net8.0;net10.0 true true enable diff --git a/Dapper/Dapper.csproj b/Dapper/Dapper.csproj index af5febfb8..98d8f11eb 100644 --- a/Dapper/Dapper.csproj +++ b/Dapper/Dapper.csproj @@ -5,7 +5,7 @@ orm;sql;micro-orm A high performance Micro-ORM supporting SQL Server, MySQL, Sqlite, SqlCE, Firebird etc. Major Sponsor: Dapper Plus from ZZZ Projects. Sam Saffron;Marc Gravell;Nick Craver - net461;netstandard2.0;net8.0 + net461;netstandard2.0;net8.0;net10.0 enable true diff --git a/global.json b/global.json index 2cbaab19b..f7b5e40c2 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.101", + "version": "10.0.102", "rollForward": "latestMajor" } } \ No newline at end of file diff --git a/tests/Dapper.Tests/Dapper.Tests.csproj b/tests/Dapper.Tests/Dapper.Tests.csproj index 4c242bf81..e02bb4ba3 100644 --- a/tests/Dapper.Tests/Dapper.Tests.csproj +++ b/tests/Dapper.Tests/Dapper.Tests.csproj @@ -2,7 +2,7 @@ Dapper.Tests Dapper Core Test Suite - net481;net8.0;net9.0 + net481;net8.0;net10.0 $(DefineConstants);MSSQLCLIENT $(NoWarn);IDE0017;IDE0034;IDE0037;IDE0039;IDE0042;IDE0044;IDE0051;IDE0052;IDE0059;IDE0060;IDE0063;IDE1006;xUnit1004;CA1806;CA1816;CA1822;CA1825;CA2208;CA1861 enable From 155a83319a0b36b66f3e9317241f686b4e6bd1e6 Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Wed, 29 Apr 2026 06:23:17 +0100 Subject: [PATCH 07/13] fix CI (#2196) * fix CI * try again --- appveyor.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index ae9d477bf..5ec88faaf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,6 +6,11 @@ skip_commits: files: - '**/*.md' +install: +- ps: | + Invoke-WebRequest -Uri 'https://dot.net/v1/dotnet-install.ps1' -UseBasicParsing -OutFile "$env:temp\dotnet-install.ps1" + & $env:temp\dotnet-install.ps1 -Architecture x64 -Version '10.0.102' -InstallDir "$env:ProgramFiles\dotnet" + environment: Appveyor: true # Postgres From b9bdd7c40be9adec3f9f556ffe00acfda77a0604 Mon Sep 17 00:00:00 2001 From: Andi Date: Wed, 29 Apr 2026 08:29:21 +0200 Subject: [PATCH 08/13] Fix segfault when ICustomQueryParameter is a value type (#2189) (#2198) The IL emitted by CreateParamInfoGenerator used Callvirt to invoke AddParameter on an unboxed struct sitting on the evaluation stack. Callvirt expects a reference, so the CLR misinterpreted the raw struct bytes as an object pointer, causing a fatal CLR error (0x80131506). --- Dapper/SqlMapper.cs | 8 +++++-- tests/Dapper.Tests/ParameterTests.cs | 34 ++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs index d23e949a5..e87a017bf 100644 --- a/Dapper/SqlMapper.cs +++ b/Dapper/SqlMapper.cs @@ -2666,7 +2666,11 @@ private static bool IsValueTuple(Type? type) => (type?.IsValueType == true { il.Emit(OpCodes.Ldloc, typedParameterLocal); // stack is now [parameters] [typed-param] il.Emit(callOpCode, prop.GetGetMethod()!); // stack is [parameters] [custom] - if (!prop.PropertyType.IsValueType) + if (prop.PropertyType.IsValueType) + { + il.Emit(OpCodes.Box, prop.PropertyType); // stack is [parameters] [boxed-custom] + } + else { // throw if null var notNull = il.DefineLabel(); @@ -2678,7 +2682,7 @@ private static bool IsValueTuple(Type? type) => (type?.IsValueType == true } il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [custom] [command] il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [custom] [command] [name] - il.EmitCall(OpCodes.Callvirt, prop.PropertyType.GetMethod(nameof(ICustomQueryParameter.AddParameter))!, null); // stack is now [parameters] + il.EmitCall(OpCodes.Callvirt, typeof(ICustomQueryParameter).GetMethod(nameof(ICustomQueryParameter.AddParameter))!, null); // stack is now [parameters] continue; } #pragma warning disable 618 diff --git a/tests/Dapper.Tests/ParameterTests.cs b/tests/Dapper.Tests/ParameterTests.cs index 650624c20..5eb455c65 100644 --- a/tests/Dapper.Tests/ParameterTests.cs +++ b/tests/Dapper.Tests/ParameterTests.cs @@ -61,6 +61,21 @@ public void AddParameter(IDbCommand command, string name) } } + public readonly struct DbCustomParamStruct : SqlMapper.ICustomQueryParameter + { + private readonly IDbDataParameter _sqlParameter; + + public DbCustomParamStruct(IDbDataParameter sqlParameter) + { + _sqlParameter = sqlParameter; + } + + public void AddParameter(IDbCommand command, string name) + { + command.Parameters.Add(_sqlParameter); + } + } + private static IEnumerable CreateSqlDataRecordList(IDbCommand command, IEnumerable numbers) { #pragma warning disable CS0618 // Type or member is obsolete @@ -885,8 +900,23 @@ public void TestCustomParameterReuse() Assert.Equal(123, result2.Foo); Assert.Equal("abc", result2.Bar); } - - + + [Fact] + public void TestCustomParameterValueType() + { + // Value type (struct) ICustomQueryParameter previously caused a segfault + // because the IL emitted Callvirt on an unboxed struct (see #2189) + var args = new { + foo = new DbCustomParamStruct(Provider.CreateRawParameter("foo", 123)), + bar = "abc" + }; + var result = connection.Query("select Foo=@foo, Bar=@bar", args).Single(); + int foo = result.Foo; + string bar = result.Bar; + Assert.Equal(123, foo); + Assert.Equal("abc", bar); + } + [Fact] public void TestDynamicParamNullSupport() { From 464cb337ba9a2989a190a58b608d0d5afb3b6494 Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Wed, 29 Apr 2026 08:38:12 +0100 Subject: [PATCH 09/13] Update dependencies (#2202) * first snapshot, warnings * intermediate * more * more fixings * cleanup * nuke NETCOREAPP3_1 ref --- Dapper.StrongName/Dapper.StrongName.csproj | 2 + Dapper/Dapper.csproj | 2 + Directory.Build.props | 2 +- Directory.Packages.props | 53 ++++++++++--------- .../Dapper.Tests.Performance.csproj | 18 ++++--- tests/Dapper.Tests/Dapper.Tests.csproj | 3 +- tests/Dapper.Tests/MiscTests.cs | 2 +- 7 files changed, 46 insertions(+), 36 deletions(-) diff --git a/Dapper.StrongName/Dapper.StrongName.csproj b/Dapper.StrongName/Dapper.StrongName.csproj index 2aae43d73..705385fd6 100644 --- a/Dapper.StrongName/Dapper.StrongName.csproj +++ b/Dapper.StrongName/Dapper.StrongName.csproj @@ -19,10 +19,12 @@ + + diff --git a/Dapper/Dapper.csproj b/Dapper/Dapper.csproj index 98d8f11eb..d9518dc45 100644 --- a/Dapper/Dapper.csproj +++ b/Dapper/Dapper.csproj @@ -26,10 +26,12 @@ + + diff --git a/Directory.Build.props b/Directory.Build.props index cb8af4d2d..227e4eed5 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,7 +14,7 @@ git https://github.com/DapperLib/Dapper false - $(NOWARN);IDE0056;IDE0057;IDE0079 + $(NOWARN);IDE0056;IDE0057;IDE0079;DX1001 true embedded en-US diff --git a/Directory.Packages.props b/Directory.Packages.props index 8787a7767..19c2ac3a3 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,50 +3,53 @@ + - + - - + + - + - - + + - - - - + + + + - - - - - + + + + + + - - + + - + - - + + - - + + - + + - + - + \ No newline at end of file diff --git a/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj b/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj index fa18bd9c5..f9692833a 100644 --- a/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj +++ b/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj @@ -3,7 +3,7 @@ Dapper.Tests.Performance Dapper Core Performance Suite Exe - net462;net8.0 + net472;net10.0 false $(NoWarn);IDE0063;IDE0034;IDE0059;IDE0060 @@ -27,14 +27,16 @@ + + - + - - + + @@ -50,20 +52,20 @@ - + $(DefineConstants);NET4X - + - + - + diff --git a/tests/Dapper.Tests/Dapper.Tests.csproj b/tests/Dapper.Tests/Dapper.Tests.csproj index e02bb4ba3..17e3f1cc6 100644 --- a/tests/Dapper.Tests/Dapper.Tests.csproj +++ b/tests/Dapper.Tests/Dapper.Tests.csproj @@ -24,6 +24,7 @@ + @@ -32,7 +33,7 @@ - + diff --git a/tests/Dapper.Tests/MiscTests.cs b/tests/Dapper.Tests/MiscTests.cs index 9323be671..077e93647 100644 --- a/tests/Dapper.Tests/MiscTests.cs +++ b/tests/Dapper.Tests/MiscTests.cs @@ -9,7 +9,7 @@ using Microsoft.CSharp.RuntimeBinder; using Xunit; -#if NETCOREAPP3_1 || NET462 || NET472 +#if NET472 namespace System.Runtime.CompilerServices { [EditorBrowsable(EditorBrowsableState.Never)] From 512f024667b79b4a17a38f33da59b072a43579f1 Mon Sep 17 00:00:00 2001 From: Henrik Date: Wed, 29 Apr 2026 09:39:02 +0200 Subject: [PATCH 10/13] Make private & internal classes sealed and less enumeration of lists & LINQ (#2197) --- Dapper.SqlBuilder/SqlBuilder.cs | 12 ++++------ Dapper/DefaultTypeMap.cs | 24 +++++++++---------- Dapper/DynamicParameters.cs | 14 ++--------- Dapper/FeatureSupport.cs | 2 +- Dapper/SqlMapper.CacheInfo.cs | 2 +- Dapper/SqlMapper.DontMap.cs | 2 +- Dapper/SqlMapper.Link.cs | 2 +- Dapper/SqlMapper.TypeDeserializerCache.cs | 2 +- Dapper/SqlMapper.cs | 8 +++---- .../Massive/Massive.cs | 1 - .../PetaPoco/PetaPoco.cs | 9 ++++--- 11 files changed, 32 insertions(+), 46 deletions(-) diff --git a/Dapper.SqlBuilder/SqlBuilder.cs b/Dapper.SqlBuilder/SqlBuilder.cs index 5726fdc6e..cb45d0582 100644 --- a/Dapper.SqlBuilder/SqlBuilder.cs +++ b/Dapper.SqlBuilder/SqlBuilder.cs @@ -10,7 +10,7 @@ public class SqlBuilder private readonly Dictionary _data = new Dictionary(); private int _seq; - private class Clause + private sealed class Clause { public Clause(string sql, object? parameters, bool isInclusive) { @@ -23,7 +23,7 @@ public Clause(string sql, object? parameters, bool isInclusive) public bool IsInclusive { get; } } - private class Clauses : List + private sealed class Clauses : List { private readonly string _joiner, _prefix, _postfix; @@ -36,11 +36,9 @@ public Clauses(string joiner, string prefix = "", string postfix = "") public string ResolveClauses(DynamicParameters p) { - foreach (var item in this) - { - p.AddDynamicParams(item.Parameters); - } - return this.Any(a => a.IsInclusive) + ForEach(item => p.AddDynamicParams(item.Parameters)); + + return Exists(a => a.IsInclusive) ? _prefix + string.Join(_joiner, this.Where(a => !a.IsInclusive) diff --git a/Dapper/DefaultTypeMap.cs b/Dapper/DefaultTypeMap.cs index 98029741a..c2f691883 100644 --- a/Dapper/DefaultTypeMap.cs +++ b/Dapper/DefaultTypeMap.cs @@ -10,7 +10,7 @@ namespace Dapper /// public sealed class DefaultTypeMap : SqlMapper.ITypeMap { - private readonly List _fields; + private readonly FieldInfo[] _fields; private readonly Type _type; /// @@ -42,7 +42,7 @@ internal static MethodInfo GetPropertySetterOrThrow(PropertyInfo propertyInfo, T BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, Type.DefaultBinder, propertyInfo.PropertyType, - propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray(), + Array.ConvertAll(propertyInfo.GetIndexParameters(), p => p.ParameterType), null)!.GetSetMethod(true); } @@ -54,9 +54,9 @@ internal static List GetSettableProps(Type t) .ToList(); } - internal static List GetSettableFields(Type t) + private static FieldInfo[] GetSettableFields(Type t) { - return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).ToList(); + return t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); } /// @@ -156,20 +156,20 @@ public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, // preference order is: // exact match over underscore match, exact case over wrong case, backing fields over regular fields, match-inc-underscores over match-exc-underscores - var field = _fields.Find(p => string.Equals(p.Name, columnName, StringComparison.Ordinal)) - ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal)) - ?? _fields.Find(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase)) - ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase)); + var field = Array.Find(_fields, p => string.Equals(p.Name, columnName, StringComparison.Ordinal)) + ?? Array.Find(_fields, p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal)) + ?? Array.Find(_fields, p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase)) + ?? Array.Find(_fields, p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase)); if (field is null && MatchNamesWithUnderscores) { var effectiveColumnName = columnName.Replace("_", ""); backingFieldName = "<" + effectiveColumnName + ">k__BackingField"; - field = _fields.Find(p => string.Equals(p.Name, effectiveColumnName, StringComparison.Ordinal)) - ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal)) - ?? _fields.Find(p => string.Equals(p.Name, effectiveColumnName, StringComparison.OrdinalIgnoreCase)) - ?? _fields.Find(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase)); + field = Array.Find(_fields, p => string.Equals(p.Name, effectiveColumnName, StringComparison.Ordinal)) + ?? Array.Find(_fields, p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal)) + ?? Array.Find(_fields, p => string.Equals(p.Name, effectiveColumnName, StringComparison.OrdinalIgnoreCase)) + ?? Array.Find(_fields, p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase)); } if (field is not null) diff --git a/Dapper/DynamicParameters.cs b/Dapper/DynamicParameters.cs index f6708b5ce..1feb4d020 100644 --- a/Dapper/DynamicParameters.cs +++ b/Dapper/DynamicParameters.cs @@ -62,10 +62,7 @@ public void AddDynamicParams(object? param) if (subDynamic.templates is not null) { templates ??= new List(); - foreach (var t in subDynamic.templates) - { - templates.Add(t); - } + templates.AddRange(subDynamic.templates); } } else @@ -212,14 +209,7 @@ protected void AddParameters(IDbCommand command, SqlMapper.Identity identity) } // Now that the parameters are added to the command, let's place our output callbacks - var tmp = outputCallbacks; - if (tmp is not null) - { - foreach (var generator in tmp) - { - generator(); - } - } + outputCallbacks?.ForEach(generator => generator()); } foreach (var param in parameters.Values) diff --git a/Dapper/FeatureSupport.cs b/Dapper/FeatureSupport.cs index 4d7d77e2e..f00c38ed3 100644 --- a/Dapper/FeatureSupport.cs +++ b/Dapper/FeatureSupport.cs @@ -6,7 +6,7 @@ namespace Dapper /// /// Handles variances in features per DBMS /// - internal class FeatureSupport + internal sealed class FeatureSupport { private static readonly FeatureSupport Default = new FeatureSupport(false), diff --git a/Dapper/SqlMapper.CacheInfo.cs b/Dapper/SqlMapper.CacheInfo.cs index d235beb6f..69edc4eea 100644 --- a/Dapper/SqlMapper.CacheInfo.cs +++ b/Dapper/SqlMapper.CacheInfo.cs @@ -7,7 +7,7 @@ namespace Dapper { public static partial class SqlMapper { - private class CacheInfo + private sealed class CacheInfo { public DeserializerState Deserializer { get; set; } public Func[]? OtherDeserializers { get; set; } diff --git a/Dapper/SqlMapper.DontMap.cs b/Dapper/SqlMapper.DontMap.cs index a97c5811e..765c7b937 100644 --- a/Dapper/SqlMapper.DontMap.cs +++ b/Dapper/SqlMapper.DontMap.cs @@ -5,6 +5,6 @@ public static partial class SqlMapper /// /// Dummy type for excluding from multi-map /// - private class DontMap { /* hiding constructor */ } + private sealed class DontMap { /* hiding constructor */ } } } diff --git a/Dapper/SqlMapper.Link.cs b/Dapper/SqlMapper.Link.cs index 92b434881..710714412 100644 --- a/Dapper/SqlMapper.Link.cs +++ b/Dapper/SqlMapper.Link.cs @@ -12,7 +12,7 @@ public static partial class SqlMapper /// /// The type to cache. /// The value type of the cache. - internal class Link where TKey : class + internal sealed class Link where TKey : class { public static void Clear(ref Link? head) => Interlocked.Exchange(ref head, null); public static bool TryGet(Link? link, TKey key, [NotNullWhen(true)] out TValue? value) diff --git a/Dapper/SqlMapper.TypeDeserializerCache.cs b/Dapper/SqlMapper.TypeDeserializerCache.cs index 2c2f646db..3a34cd292 100644 --- a/Dapper/SqlMapper.TypeDeserializerCache.cs +++ b/Dapper/SqlMapper.TypeDeserializerCache.cs @@ -8,7 +8,7 @@ namespace Dapper { public static partial class SqlMapper { - private class TypeDeserializerCache + private sealed class TypeDeserializerCache { private TypeDeserializerCache(Type type) { diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs index e87a017bf..6c8fe844e 100644 --- a/Dapper/SqlMapper.cs +++ b/Dapper/SqlMapper.cs @@ -29,7 +29,7 @@ namespace Dapper /// public static partial class SqlMapper { - private class PropertyInfoByNameComparer : IComparer + private sealed class PropertyInfoByNameComparer : IComparer { public int Compare(PropertyInfo? x, PropertyInfo? y) => string.CompareOrdinal(x?.Name, y?.Name); } @@ -3534,9 +3534,9 @@ private static void GenerateDeserializerFromMap(Type type, DbDataReader reader, il.Emit(OpCodes.Ldloc, returnValueLocal); // [target] } - var members = (specializedConstructor is not null - ? names.Select(n => typeMap.GetConstructorParameter(specializedConstructor, n)) - : names.Select(n => typeMap.GetMember(n))).ToList(); + var members = Array.ConvertAll(names, specializedConstructor is not null + ? n => typeMap.GetConstructorParameter(specializedConstructor, n) + : n => typeMap.GetMember(n)); // stack is now [target] bool first = true; diff --git a/benchmarks/Dapper.Tests.Performance/Massive/Massive.cs b/benchmarks/Dapper.Tests.Performance/Massive/Massive.cs index f452a95cb..f4c1c8192 100644 --- a/benchmarks/Dapper.Tests.Performance/Massive/Massive.cs +++ b/benchmarks/Dapper.Tests.Performance/Massive/Massive.cs @@ -322,7 +322,6 @@ public virtual DbCommand CreateUpdateCommand(object o, object key) var settings = (IDictionary)expando; var sbKeys = new StringBuilder(); const string stub = "UPDATE {0} SET {1} WHERE {2} = @{3}"; - var args = new List(); var result = CreateCommand(stub, null); int counter = 0; foreach (var item in settings) diff --git a/benchmarks/Dapper.Tests.Performance/PetaPoco/PetaPoco.cs b/benchmarks/Dapper.Tests.Performance/PetaPoco/PetaPoco.cs index add3df772..2ffa3887c 100644 --- a/benchmarks/Dapper.Tests.Performance/PetaPoco/PetaPoco.cs +++ b/benchmarks/Dapper.Tests.Performance/PetaPoco/PetaPoco.cs @@ -1020,10 +1020,9 @@ public string LastCommand { get { - var sb = new StringBuilder(); if (_lastSql == null) return ""; - sb.Append(_lastSql); + var sb = new StringBuilder(_lastSql); if (_lastArgs != null) { sb.Append("\r\n\r\n"); @@ -1038,14 +1037,14 @@ public string LastCommand public static IMapper Mapper { get; set; } - internal class PocoColumn + internal sealed class PocoColumn { public string ColumnName; public PropertyInfo PropertyInfo; public bool ResultColumn; } - internal class PocoData + internal sealed class PocoData { public static PocoData ForType(Type t) { @@ -1272,7 +1271,7 @@ public Func GetFactory(string key, bool ForceDateTimesToUtc, // ShareableConnection represents either a shared connection used by a transaction, // or a one-off connection if not in a transaction. // Non-shared connections are disposed - private class ShareableConnection : IDisposable + private sealed class ShareableConnection : IDisposable { public ShareableConnection(Database db) { From 2a8faab235c21892fb4c9a4529510d030516d691 Mon Sep 17 00:00:00 2001 From: Andi Date: Sat, 16 May 2026 22:08:03 +0200 Subject: [PATCH 11/13] Fix/prefer typehandlers for enums (#2200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Settings.PreferTypeHandlersForEnums opt-in flag When enabled, Dapper checks for a registered TypeHandler for enum types before falling back to the default integer boxing behavior. This allows custom enum serialization (e.g. storing enums as strings via TypeHandlers) to work on both reads and writes. Patched locations: - LookupDbType: return DbType.Object with handler when flag is on - CreateParamInfoGenerator: skip integer boxing when handler exists - GetSimpleValueDeserializer: route to TypeHandler before Enum.ToObject - Parse: route to TypeHandler before Enum.ToObject Default is false — zero behavior change for existing users. * Patch IL-emitted type deserializer and add tests - Fix 6th enum-before-handler location in GetTypeDeserializer IL emit, preserving Nullable wrapping for nullable enum properties - Fix em-dash in comment (non-ASCII) - Add two tests: round-trip write+read via StringEnumHandler, and nullable enum with null value * Update SDK version from 10.0.102 to 8.0.100 * Update global.json we have fixed the CI glitch separately --------- Co-authored-by: Marc Gravell --- Dapper/PublicAPI.Unshipped.txt | 4 +- Dapper/SqlMapper.Settings.cs | 9 +- Dapper/SqlMapper.cs | 59 ++++++--- global.json | 2 +- .../PreferTypeHandlersForEnumsTests.cs | 112 ++++++++++++++++++ 5 files changed, 169 insertions(+), 17 deletions(-) create mode 100644 tests/Dapper.Tests/PreferTypeHandlersForEnumsTests.cs diff --git a/Dapper/PublicAPI.Unshipped.txt b/Dapper/PublicAPI.Unshipped.txt index 91b0e1a43..cf9343ccf 100644 --- a/Dapper/PublicAPI.Unshipped.txt +++ b/Dapper/PublicAPI.Unshipped.txt @@ -1 +1,3 @@ -#nullable enable \ No newline at end of file +#nullable enable +static Dapper.SqlMapper.Settings.PreferTypeHandlersForEnums.get -> bool +static Dapper.SqlMapper.Settings.PreferTypeHandlersForEnums.set -> void \ No newline at end of file diff --git a/Dapper/SqlMapper.Settings.cs b/Dapper/SqlMapper.Settings.cs index cbbc3c687..c19835c11 100644 --- a/Dapper/SqlMapper.Settings.cs +++ b/Dapper/SqlMapper.Settings.cs @@ -65,7 +65,7 @@ static Settings() public static void SetDefaults() { CommandTimeout = null; - ApplyNullValues = PadListExpansions = UseIncrementalPseudoPositionalParameterNames = false; + ApplyNullValues = PadListExpansions = UseIncrementalPseudoPositionalParameterNames = PreferTypeHandlersForEnums = false; AllowedCommandBehaviors = DefaultAllowedCommandBehaviors; FetchSize = InListStringSplitCount = -1; } @@ -129,6 +129,13 @@ public static long FetchSize /// public static bool SupportLegacyParameterTokens { get; set; } = true; + /// + /// When true, Dapper checks for a registered TypeHandler for enum types before + /// falling back to the default behavior of sending enums as their underlying integer type. + /// This enables custom enum serialization (e.g. storing enums as strings), while preserving existing behavior. + /// + public static bool PreferTypeHandlersForEnums { get; set; } + private static long s_FetchSize = -1; } } diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs index 6c8fe844e..2fa0e72b7 100644 --- a/Dapper/SqlMapper.cs +++ b/Dapper/SqlMapper.cs @@ -465,6 +465,10 @@ public static void SetDbType(IDataParameter parameter, object value) if (nullUnderlyingType is not null) type = nullUnderlyingType; if (type.IsEnum && !typeMap.ContainsKey(type)) { + if (Settings.PreferTypeHandlersForEnums && typeHandlers.TryGetValue(type, out handler)) + { + return DbType.Object; + } type = Enum.GetUnderlyingType(type); } if (typeMap.TryGetValue(type, out var mapEntry)) @@ -2755,7 +2759,12 @@ private static bool IsValueTuple(Type? type) => (type?.IsValueType == true if ((nullType ?? propType).IsEnum) { - if (nullType is not null) + if (handler is not null) + { + // TypeHandler registered - box as the enum type, handler does conversion + checkForNull = nullType is not null; + } + else if (nullType is not null) { // Nullable; we want to box as the underlying type; that's just *hard*; for // simplicity, box as Nullable and call SanitizeParameterValue @@ -3101,7 +3110,16 @@ private static Func GetSimpleValueDeserializer(Type type, #pragma warning restore 618 if (effectiveType.IsEnum) - { // assume the value is returned as the correct type (int/byte/etc), but box back to the typed enum + { + if (Settings.PreferTypeHandlersForEnums && typeHandlers.TryGetValue(type, out var enumHandler)) + { + return r => + { + var val = r.GetValue(index); + return val is DBNull ? null! : enumHandler.Parse(type, val)!; + }; + } + // assume the value is returned as the correct type (int/byte/etc), but box back to the typed enum return r => { var val = r.GetValue(index); @@ -3164,6 +3182,10 @@ private static T Parse(object? value) type = Nullable.GetUnderlyingType(type) ?? type; if (type.IsEnum) { + if (Settings.PreferTypeHandlersForEnums && typeHandlers.TryGetValue(type, out ITypeHandler? enumHandler)) + { + return (T)enumHandler.Parse(type, value)!; + } if (value is float || value is double || value is decimal) { value = Convert.ChangeType(value, Enum.GetUnderlyingType(type), CultureInfo.InvariantCulture); @@ -3742,22 +3764,31 @@ private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int ind if (unboxType.IsEnum) { - Type numericType = Enum.GetUnderlyingType(unboxType); - if (colType == typeof(string)) + if (Settings.PreferTypeHandlersForEnums && typeHandlers.ContainsKey(unboxType)) { - stringEnumLocal ??= il.DeclareLocal(typeof(string)); - il.Emit(OpCodes.Castclass, typeof(string)); // stack is now [...][string] - il.Emit(OpCodes.Stloc, stringEnumLocal); // stack is now [...] - il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [...][enum-type-token] - il.EmitCall(OpCodes.Call, typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle))!, null);// stack is now [...][enum-type] - il.Emit(OpCodes.Ldloc, stringEnumLocal); // stack is now [...][enum-type][string] - il.Emit(OpCodes.Ldc_I4_1); // stack is now [...][enum-type][string][true] - il.EmitCall(OpCodes.Call, enumParse, null); // stack is now [...][enum-as-object] - il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [...][typed-value] +#pragma warning disable 618 + il.EmitCall(OpCodes.Call, typeof(TypeHandlerCache<>).MakeGenericType(unboxType).GetMethod(nameof(TypeHandlerCache.Parse))!, null); // stack is now [...][typed-value] +#pragma warning restore 618 } else { - FlexibleConvertBoxedFromHeadOfStack(il, colType, unboxType, numericType); + Type numericType = Enum.GetUnderlyingType(unboxType); + if (colType == typeof(string)) + { + stringEnumLocal ??= il.DeclareLocal(typeof(string)); + il.Emit(OpCodes.Castclass, typeof(string)); // stack is now [...][string] + il.Emit(OpCodes.Stloc, stringEnumLocal); // stack is now [...] + il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [...][enum-type-token] + il.EmitCall(OpCodes.Call, typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle))!, null);// stack is now [...][enum-type] + il.Emit(OpCodes.Ldloc, stringEnumLocal); // stack is now [...][enum-type][string] + il.Emit(OpCodes.Ldc_I4_1); // stack is now [...][enum-type][string][true] + il.EmitCall(OpCodes.Call, enumParse, null); // stack is now [...][enum-as-object] + il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [...][typed-value] + } + else + { + FlexibleConvertBoxedFromHeadOfStack(il, colType, unboxType, numericType); + } } if (nullUnderlyingType is not null) diff --git a/global.json b/global.json index f7b5e40c2..1e3e94a0b 100644 --- a/global.json +++ b/global.json @@ -3,4 +3,4 @@ "version": "10.0.102", "rollForward": "latestMajor" } -} \ No newline at end of file +} diff --git a/tests/Dapper.Tests/PreferTypeHandlersForEnumsTests.cs b/tests/Dapper.Tests/PreferTypeHandlersForEnumsTests.cs new file mode 100644 index 000000000..958f0d546 --- /dev/null +++ b/tests/Dapper.Tests/PreferTypeHandlersForEnumsTests.cs @@ -0,0 +1,112 @@ +using System; +using System.Data; +using System.Linq; +using Xunit; + +namespace Dapper.Tests +{ + [Collection(NonParallelDefinition.Name)] + public sealed class SystemSqlClientPreferTypeHandlersForEnumsTests : PreferTypeHandlersForEnumsTests { } +#if MSSQLCLIENT + [Collection(NonParallelDefinition.Name)] + public sealed class MicrosoftSqlClientPreferTypeHandlersForEnumsTests : PreferTypeHandlersForEnumsTests { } +#endif + + public abstract class PreferTypeHandlersForEnumsTests : TestBase where TProvider : DatabaseProvider + { + private enum Color + { + Red = 1, + Green = 2, + Blue = 3 + } + + private class ColorResult + { + public Color Value { get; set; } + } + + private class NullableColorResult + { + public Color? Value { get; set; } + } + + /// + /// A TypeHandler that stores enum values as their name strings + /// and parses them back from strings. + /// + private class StringEnumHandler : SqlMapper.TypeHandler where TEnum : struct, Enum + { + public static readonly StringEnumHandler Instance = new(); + public int ParseCallCount; + public int SetValueCallCount; + + public override TEnum Parse(object? value) + { + ParseCallCount++; + return (TEnum)Enum.Parse(typeof(TEnum), (string)value!); + } + + public override void SetValue(IDbDataParameter parameter, TEnum value) + { + SetValueCallCount++; + parameter.DbType = DbType.AnsiString; + parameter.Value = value.ToString(); + } + } + + [Fact] + public void EnumTypeHandler_WriteAndRead_UsesHandlerWhenEnabled() + { + var handler = new StringEnumHandler(); + var oldSetting = SqlMapper.Settings.PreferTypeHandlersForEnums; + try + { + SqlMapper.ResetTypeHandlers(); + SqlMapper.AddTypeHandler(typeof(Color), handler); + SqlMapper.Settings.PreferTypeHandlersForEnums = true; + SqlMapper.PurgeQueryCache(); + + // Round-trip: write as string, read back via handler + var result = connection.Query( + "SELECT @Value AS Value", new { Value = Color.Green }).Single(); + + Assert.Equal(Color.Green, result.Value); + Assert.True(handler.SetValueCallCount > 0, "SetValue should have been called"); + Assert.True(handler.ParseCallCount > 0, "Parse should have been called"); + } + finally + { + SqlMapper.Settings.PreferTypeHandlersForEnums = oldSetting; + SqlMapper.ResetTypeHandlers(); + SqlMapper.PurgeQueryCache(); + } + } + + [Fact] + public void EnumTypeHandler_NullableWithNull_ReturnsNull() + { + var handler = new StringEnumHandler(); + var oldSetting = SqlMapper.Settings.PreferTypeHandlersForEnums; + try + { + SqlMapper.ResetTypeHandlers(); + SqlMapper.AddTypeHandler(typeof(Color), handler); + SqlMapper.Settings.PreferTypeHandlersForEnums = true; + SqlMapper.PurgeQueryCache(); + + Color? input = null; + var result = connection.Query( + "SELECT @Value AS Value", new { Value = input }).Single(); + + Assert.Null(result.Value); + } + finally + { + SqlMapper.Settings.PreferTypeHandlersForEnums = oldSetting; + SqlMapper.ResetTypeHandlers(); + SqlMapper.PurgeQueryCache(); + } + } + } +} From 953f3718052940e72d0f20e22d836b1595f5dcd8 Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Sat, 16 May 2026 21:08:13 +0100 Subject: [PATCH 12/13] keep deps up to date (#2204) * keep deps up to date * d'oh * slnx --- Dapper.sln => Dapper.sln.old | 242 +++++++++--------- Dapper.slnx | 38 +++ Directory.Packages.props | 18 +- .../Dapper.Tests.Performance.csproj | 2 +- tests/Dapper.Tests/Dapper.Tests.csproj | 8 +- 5 files changed, 175 insertions(+), 133 deletions(-) rename Dapper.sln => Dapper.sln.old (98%) create mode 100644 Dapper.slnx diff --git a/Dapper.sln b/Dapper.sln.old similarity index 98% rename from Dapper.sln rename to Dapper.sln.old index 04fcc008d..e324cc009 100644 --- a/Dapper.sln +++ b/Dapper.sln.old @@ -1,121 +1,121 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.7.33906.173 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A34907DF-958A-4E4C-8491-84CF303FD13E}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - appveyor.yml = appveyor.yml - Build.csproj = Build.csproj - build.ps1 = build.ps1 - Dapper.png = Dapper.png - Directory.Build.props = Directory.Build.props - Directory.Packages.props = Directory.Packages.props - global.json = global.json - docs\index.md = docs\index.md - License.txt = License.txt - .github\workflows\main.yml = .github\workflows\main.yml - NonCLA.md = NonCLA.md - nuget.config = nuget.config - Readme.md = Readme.md - version.json = version.json - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper", "Dapper\Dapper.csproj", "{FAC24C3F-68F9-4247-A4B9-21D487E99275}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.StrongName", "Dapper.StrongName\Dapper.StrongName.csproj", "{549C51A1-222B-4E12-96F1-3AEFF45A7709}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Tests", "tests\Dapper.Tests\Dapper.Tests.csproj", "{052C0817-DB26-4925-8929-8C5E42D148D5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.EntityFramework", "Dapper.EntityFramework\Dapper.EntityFramework.csproj", "{BE401F7B-8611-4A1E-AEAA-5CB700128C16}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.SqlBuilder", "Dapper.SqlBuilder\Dapper.SqlBuilder.csproj", "{196928F0-7052-4585-90E8-817BD720F5E3}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Rainbow", "Dapper.Rainbow\Dapper.Rainbow.csproj", "{8A74F0B6-188F-45D2-8A4B-51E4F211805A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4E956F6B-6BD8-46F5-BC85-49292FF8F9AB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{568BD46C-1C65-4D44-870C-12CD72563262}" - ProjectSection(SolutionItems) = preProject - tests\Directory.Build.props = tests\Directory.Build.props - tests\Directory.Build.targets = tests\Directory.Build.targets - tests\docker-compose.yml = tests\docker-compose.yml - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.EntityFramework.StrongName", "Dapper.EntityFramework.StrongName\Dapper.EntityFramework.StrongName.csproj", "{39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Tests.Performance", "benchmarks\Dapper.Tests.Performance\Dapper.Tests.Performance.csproj", "{F017075A-2969-4A8E-8971-26F154EB420F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.ProviderTools", "Dapper.ProviderTools\Dapper.ProviderTools.csproj", "{B06DB435-0C74-4BD3-BC97-52AF7CF9916B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{9D960D4D-80A2-4DAC-B386-8F4235EC73E6}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "docs", "docs\docs.csproj", "{C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FAC24C3F-68F9-4247-A4B9-21D487E99275}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FAC24C3F-68F9-4247-A4B9-21D487E99275}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FAC24C3F-68F9-4247-A4B9-21D487E99275}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FAC24C3F-68F9-4247-A4B9-21D487E99275}.Release|Any CPU.Build.0 = Release|Any CPU - {549C51A1-222B-4E12-96F1-3AEFF45A7709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {549C51A1-222B-4E12-96F1-3AEFF45A7709}.Debug|Any CPU.Build.0 = Debug|Any CPU - {549C51A1-222B-4E12-96F1-3AEFF45A7709}.Release|Any CPU.ActiveCfg = Release|Any CPU - {549C51A1-222B-4E12-96F1-3AEFF45A7709}.Release|Any CPU.Build.0 = Release|Any CPU - {052C0817-DB26-4925-8929-8C5E42D148D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {052C0817-DB26-4925-8929-8C5E42D148D5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {052C0817-DB26-4925-8929-8C5E42D148D5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {052C0817-DB26-4925-8929-8C5E42D148D5}.Release|Any CPU.Build.0 = Release|Any CPU - {BE401F7B-8611-4A1E-AEAA-5CB700128C16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BE401F7B-8611-4A1E-AEAA-5CB700128C16}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BE401F7B-8611-4A1E-AEAA-5CB700128C16}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BE401F7B-8611-4A1E-AEAA-5CB700128C16}.Release|Any CPU.Build.0 = Release|Any CPU - {196928F0-7052-4585-90E8-817BD720F5E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {196928F0-7052-4585-90E8-817BD720F5E3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {196928F0-7052-4585-90E8-817BD720F5E3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {196928F0-7052-4585-90E8-817BD720F5E3}.Release|Any CPU.Build.0 = Release|Any CPU - {8A74F0B6-188F-45D2-8A4B-51E4F211805A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8A74F0B6-188F-45D2-8A4B-51E4F211805A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8A74F0B6-188F-45D2-8A4B-51E4F211805A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8A74F0B6-188F-45D2-8A4B-51E4F211805A}.Release|Any CPU.Build.0 = Release|Any CPU - {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}.Release|Any CPU.Build.0 = Release|Any CPU - {F017075A-2969-4A8E-8971-26F154EB420F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F017075A-2969-4A8E-8971-26F154EB420F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F017075A-2969-4A8E-8971-26F154EB420F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F017075A-2969-4A8E-8971-26F154EB420F}.Release|Any CPU.Build.0 = Release|Any CPU - {B06DB435-0C74-4BD3-BC97-52AF7CF9916B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B06DB435-0C74-4BD3-BC97-52AF7CF9916B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B06DB435-0C74-4BD3-BC97-52AF7CF9916B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B06DB435-0C74-4BD3-BC97-52AF7CF9916B}.Release|Any CPU.Build.0 = Release|Any CPU - {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {FAC24C3F-68F9-4247-A4B9-21D487E99275} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} - {549C51A1-222B-4E12-96F1-3AEFF45A7709} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} - {052C0817-DB26-4925-8929-8C5E42D148D5} = {568BD46C-1C65-4D44-870C-12CD72563262} - {BE401F7B-8611-4A1E-AEAA-5CB700128C16} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} - {196928F0-7052-4585-90E8-817BD720F5E3} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} - {8A74F0B6-188F-45D2-8A4B-51E4F211805A} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} - {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} - {F017075A-2969-4A8E-8971-26F154EB420F} = {568BD46C-1C65-4D44-870C-12CD72563262} - {B06DB435-0C74-4BD3-BC97-52AF7CF9916B} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} - {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F} = {9D960D4D-80A2-4DAC-B386-8F4235EC73E6} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {928A4226-96F3-409A-8A83-9E7444488710} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.33906.173 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A34907DF-958A-4E4C-8491-84CF303FD13E}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + appveyor.yml = appveyor.yml + Build.csproj = Build.csproj + build.ps1 = build.ps1 + Dapper.png = Dapper.png + Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props + global.json = global.json + docs\index.md = docs\index.md + License.txt = License.txt + .github\workflows\main.yml = .github\workflows\main.yml + NonCLA.md = NonCLA.md + nuget.config = nuget.config + Readme.md = Readme.md + version.json = version.json + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper", "Dapper\Dapper.csproj", "{FAC24C3F-68F9-4247-A4B9-21D487E99275}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.StrongName", "Dapper.StrongName\Dapper.StrongName.csproj", "{549C51A1-222B-4E12-96F1-3AEFF45A7709}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Tests", "tests\Dapper.Tests\Dapper.Tests.csproj", "{052C0817-DB26-4925-8929-8C5E42D148D5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.EntityFramework", "Dapper.EntityFramework\Dapper.EntityFramework.csproj", "{BE401F7B-8611-4A1E-AEAA-5CB700128C16}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.SqlBuilder", "Dapper.SqlBuilder\Dapper.SqlBuilder.csproj", "{196928F0-7052-4585-90E8-817BD720F5E3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Rainbow", "Dapper.Rainbow\Dapper.Rainbow.csproj", "{8A74F0B6-188F-45D2-8A4B-51E4F211805A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4E956F6B-6BD8-46F5-BC85-49292FF8F9AB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{568BD46C-1C65-4D44-870C-12CD72563262}" + ProjectSection(SolutionItems) = preProject + tests\Directory.Build.props = tests\Directory.Build.props + tests\Directory.Build.targets = tests\Directory.Build.targets + tests\docker-compose.yml = tests\docker-compose.yml + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.EntityFramework.StrongName", "Dapper.EntityFramework.StrongName\Dapper.EntityFramework.StrongName.csproj", "{39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.Tests.Performance", "benchmarks\Dapper.Tests.Performance\Dapper.Tests.Performance.csproj", "{F017075A-2969-4A8E-8971-26F154EB420F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapper.ProviderTools", "Dapper.ProviderTools\Dapper.ProviderTools.csproj", "{B06DB435-0C74-4BD3-BC97-52AF7CF9916B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{9D960D4D-80A2-4DAC-B386-8F4235EC73E6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "docs", "docs\docs.csproj", "{C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FAC24C3F-68F9-4247-A4B9-21D487E99275}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAC24C3F-68F9-4247-A4B9-21D487E99275}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAC24C3F-68F9-4247-A4B9-21D487E99275}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAC24C3F-68F9-4247-A4B9-21D487E99275}.Release|Any CPU.Build.0 = Release|Any CPU + {549C51A1-222B-4E12-96F1-3AEFF45A7709}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {549C51A1-222B-4E12-96F1-3AEFF45A7709}.Debug|Any CPU.Build.0 = Debug|Any CPU + {549C51A1-222B-4E12-96F1-3AEFF45A7709}.Release|Any CPU.ActiveCfg = Release|Any CPU + {549C51A1-222B-4E12-96F1-3AEFF45A7709}.Release|Any CPU.Build.0 = Release|Any CPU + {052C0817-DB26-4925-8929-8C5E42D148D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {052C0817-DB26-4925-8929-8C5E42D148D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {052C0817-DB26-4925-8929-8C5E42D148D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {052C0817-DB26-4925-8929-8C5E42D148D5}.Release|Any CPU.Build.0 = Release|Any CPU + {BE401F7B-8611-4A1E-AEAA-5CB700128C16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE401F7B-8611-4A1E-AEAA-5CB700128C16}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE401F7B-8611-4A1E-AEAA-5CB700128C16}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE401F7B-8611-4A1E-AEAA-5CB700128C16}.Release|Any CPU.Build.0 = Release|Any CPU + {196928F0-7052-4585-90E8-817BD720F5E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {196928F0-7052-4585-90E8-817BD720F5E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {196928F0-7052-4585-90E8-817BD720F5E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {196928F0-7052-4585-90E8-817BD720F5E3}.Release|Any CPU.Build.0 = Release|Any CPU + {8A74F0B6-188F-45D2-8A4B-51E4F211805A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A74F0B6-188F-45D2-8A4B-51E4F211805A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A74F0B6-188F-45D2-8A4B-51E4F211805A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A74F0B6-188F-45D2-8A4B-51E4F211805A}.Release|Any CPU.Build.0 = Release|Any CPU + {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB}.Release|Any CPU.Build.0 = Release|Any CPU + {F017075A-2969-4A8E-8971-26F154EB420F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F017075A-2969-4A8E-8971-26F154EB420F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F017075A-2969-4A8E-8971-26F154EB420F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F017075A-2969-4A8E-8971-26F154EB420F}.Release|Any CPU.Build.0 = Release|Any CPU + {B06DB435-0C74-4BD3-BC97-52AF7CF9916B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B06DB435-0C74-4BD3-BC97-52AF7CF9916B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B06DB435-0C74-4BD3-BC97-52AF7CF9916B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B06DB435-0C74-4BD3-BC97-52AF7CF9916B}.Release|Any CPU.Build.0 = Release|Any CPU + {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {FAC24C3F-68F9-4247-A4B9-21D487E99275} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} + {549C51A1-222B-4E12-96F1-3AEFF45A7709} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} + {052C0817-DB26-4925-8929-8C5E42D148D5} = {568BD46C-1C65-4D44-870C-12CD72563262} + {BE401F7B-8611-4A1E-AEAA-5CB700128C16} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} + {196928F0-7052-4585-90E8-817BD720F5E3} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} + {8A74F0B6-188F-45D2-8A4B-51E4F211805A} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} + {39D3EEB6-9C05-4F4A-8C01-7B209742A7EB} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} + {F017075A-2969-4A8E-8971-26F154EB420F} = {568BD46C-1C65-4D44-870C-12CD72563262} + {B06DB435-0C74-4BD3-BC97-52AF7CF9916B} = {4E956F6B-6BD8-46F5-BC85-49292FF8F9AB} + {C2F722AC-B2D4-4E97-AF8E-C036B3D9211F} = {9D960D4D-80A2-4DAC-B386-8F4235EC73E6} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {928A4226-96F3-409A-8A83-9E7444488710} + EndGlobalSection +EndGlobal diff --git a/Dapper.slnx b/Dapper.slnx new file mode 100644 index 000000000..674239170 --- /dev/null +++ b/Dapper.slnx @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 19c2ac3a3..aa293885e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,10 +3,10 @@ - + - + @@ -18,16 +18,16 @@ - - + + - + - - + + @@ -45,8 +45,8 @@ - - + + diff --git a/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj b/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj index f9692833a..2a229c33e 100644 --- a/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj +++ b/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj @@ -14,7 +14,7 @@ - + diff --git a/tests/Dapper.Tests/Dapper.Tests.csproj b/tests/Dapper.Tests/Dapper.Tests.csproj index 17e3f1cc6..93b498618 100644 --- a/tests/Dapper.Tests/Dapper.Tests.csproj +++ b/tests/Dapper.Tests/Dapper.Tests.csproj @@ -12,11 +12,15 @@ $(DefineConstants);ENTITY_FRAMEWORK;LINQ2SQL;OLEDB - + + + + + + - From 72a54c475f75e18cb93cba0809d00a5e6e49efd9 Mon Sep 17 00:00:00 2001 From: David Federman Date: Sat, 16 May 2026 13:25:15 -0700 Subject: [PATCH 13/13] Add ReferenceTrimmer and remove unused references (#2191) * Add ReferenceTrimmer and remove unused references * Update Directory.Packages.props latest --------- Co-authored-by: Marc Gravell --- Dapper.SqlBuilder/Dapper.SqlBuilder.csproj | 3 ++- Directory.Packages.props | 5 ++++- .../Dapper.Tests.Performance.csproj | 10 ++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Dapper.SqlBuilder/Dapper.SqlBuilder.csproj b/Dapper.SqlBuilder/Dapper.SqlBuilder.csproj index c101afcaa..a455a5941 100644 --- a/Dapper.SqlBuilder/Dapper.SqlBuilder.csproj +++ b/Dapper.SqlBuilder/Dapper.SqlBuilder.csproj @@ -19,7 +19,8 @@ - + + diff --git a/Directory.Packages.props b/Directory.Packages.props index aa293885e..252f417b9 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -52,4 +52,7 @@ - \ No newline at end of file + + + + diff --git a/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj b/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj index 2a229c33e..51c28957a 100644 --- a/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj +++ b/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj @@ -15,7 +15,6 @@ - @@ -40,11 +39,11 @@ - - - + + + - + @@ -58,7 +57,6 @@ -