diff --git a/Dapper/SqlMapper.cs b/Dapper/SqlMapper.cs index fb151758e..e23502b77 100644 --- a/Dapper/SqlMapper.cs +++ b/Dapper/SqlMapper.cs @@ -631,7 +631,7 @@ private static int ExecuteImpl(this IDbConnection cnn, ref CommandDefinition com } else { - cmd.CommandText = masterSql; // because we do magic replaces on "in" etc + cmd.CommandText = masterSql; // because we do magic replacements on "in" etc cmd.Parameters.Clear(); // current code is Add-tastic } info!.ParamReader!(cmd, obj); @@ -1944,7 +1944,7 @@ private static Func GetDeserializer(Type type, DbDataReade } return GetTypeDeserializer(type, reader, startBound, length, returnNullIfFirstMissing); } - return GetStructDeserializer(type, underlyingType ?? type, startBound, useGetFieldValue); + return GetSimpleValueDeserializer(type, underlyingType ?? type, startBound, useGetFieldValue); } private static Func GetHandlerDeserializer(ITypeHandler handler, Type type, int startBound) @@ -3049,7 +3049,7 @@ private static DbDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefi return paramReader; } - private static Func GetStructDeserializer(Type type, Type effectiveType, int index, bool useGetFieldValue) + private static Func GetSimpleValueDeserializer(Type type, Type effectiveType, int index, bool useGetFieldValue) { // no point using special per-type handling here; it boils down to the same, plus not all are supported anyway (see: SqlDataReader.GetChar - not supported!) #pragma warning disable 618 @@ -3578,8 +3578,11 @@ private static void GenerateDeserializerFromMap(Type type, DbDataReader reader, if (first && returnNullIfFirstMissing) { il.Emit(OpCodes.Pop); - il.Emit(OpCodes.Ldnull); // stack is now [null] - il.Emit(OpCodes.Stloc, returnValueLocal); + if (!type.IsValueType) // for struct, the retval is already initialized as default + { + il.Emit(OpCodes.Ldnull); // stack is now [null] + il.Emit(OpCodes.Stloc, returnValueLocal); + } il.Emit(OpCodes.Br, allDone); } diff --git a/Directory.Build.props b/Directory.Build.props index e9ebe949c..6a4b94e1c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -21,7 +21,7 @@ false true true - 11 + 12 false true readme.md diff --git a/Directory.Packages.props b/Directory.Packages.props index 06e68e627..4ddd3896f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,11 +1,10 @@ - - + @@ -13,34 +12,35 @@ - + - - - + + + + - - - - + + + + - - - - + + + + - + - - + + \ No newline at end of file diff --git a/Readme.md b/Readme.md index 769ea0e33..5991d7109 100644 --- a/Readme.md +++ b/Readme.md @@ -156,56 +156,70 @@ A key feature of Dapper is performance. The following metrics show how long it t The benchmarks can be found in [Dapper.Tests.Performance](https://github.com/DapperLib/Dapper/tree/main/benchmarks/Dapper.Tests.Performance) (contributions welcome!) and can be run via: ```bash -dotnet run --project .\benchmarks\Dapper.Tests.Performance\ -c Release -f netcoreapp3.1 -- -f * --join +dotnet run --project .\benchmarks\Dapper.Tests.Performance\ -c Release -f net8.0 -- -f * --join ``` Output from the latest run is: ``` ini -BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.208 (2004/?/20H1) -Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores -.NET Core SDK=3.1.201 - [Host] : .NET Core 3.1.3 (CoreCLR 4.700.20.11803, CoreFX 4.700.20.12001), X64 RyuJIT - ShortRun : .NET Core 3.1.3 (CoreCLR 4.700.20.11803, CoreFX 4.700.20.12001), X64 RyuJIT +BenchmarkDotNet v0.13.7, Windows 10 (10.0.19045.3693/22H2/2022Update) +Intel Core i7-3630QM CPU 2.40GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores +.NET SDK 8.0.100 + [Host] : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX + ShortRun : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX ``` -| ORM | Method | Return | Mean | StdDev | Error | Gen 0 | Gen 1 | Gen 2 | Allocated | -|--------------- |------------------------------ |-------- |----------:|----------:|----------:|--------:|-------:|-------:|----------:| -| Belgrade | ExecuteReader | Post | 94.46 μs | 8.115 μs | 12.268 μs | 1.7500 | 0.5000 | - | 8.42 KB | -| Hand Coded | DataTable | dynamic | 105.43 μs | 0.998 μs | 1.508 μs | 3.0000 | - | - | 9.37 KB | -| Hand Coded | SqlCommand | Post | 106.58 μs | 1.191 μs | 1.801 μs | 1.5000 | 0.7500 | 0.1250 | 7.42 KB | -| Dapper | QueryFirstOrDefault<dynamic> | dynamic | 119.52 μs | 1.320 μs | 2.219 μs | 3.6250 | - | - | 11.39 KB | -| Dapper | 'Query<dynamic> (buffered)' | dynamic | 119.93 μs | 1.943 μs | 2.937 μs | 2.3750 | 1.0000 | 0.2500 | 11.73 KB | -| Massive | 'Query (dynamic)' | dynamic | 120.31 μs | 1.340 μs | 2.252 μs | 2.2500 | 1.0000 | 0.1250 | 12.07 KB | -| Dapper | QueryFirstOrDefault<T> | Post | 121.57 μs | 1.564 μs | 2.364 μs | 1.7500 | 0.7500 | - | 11.35 KB | -| Dapper | 'Query<T> (buffered)' | Post | 121.67 μs | 2.913 μs | 4.403 μs | 1.8750 | 0.8750 | - | 11.65 KB | -| PetaPoco | 'Fetch<T> (Fast)' | Post | 124.91 μs | 4.015 μs | 6.747 μs | 2.0000 | 1.0000 | - | 11.5 KB | -| Mighty | Query<T> | Post | 125.23 μs | 2.932 μs | 4.433 μs | 2.2500 | 1.0000 | - | 12.6 KB | -| LINQ to DB | Query<T> | Post | 125.76 μs | 2.038 μs | 3.081 μs | 2.2500 | 0.7500 | 0.2500 | 10.62 KB | -| PetaPoco | Fetch<T> | Post | 127.48 μs | 4.283 μs | 6.475 μs | 2.0000 | 1.0000 | - | 12.18 KB | -| LINQ to DB | 'First (Compiled)' | Post | 128.89 μs | 2.627 μs | 3.971 μs | 2.5000 | 0.7500 | - | 10.92 KB | -| Mighty | Query<dynamic> | dynamic | 129.20 μs | 2.577 μs | 3.896 μs | 2.0000 | 1.0000 | - | 12.43 KB | -| Mighty | SingleFromQuery<T> | Post | 129.41 μs | 2.094 μs | 3.166 μs | 2.2500 | 1.0000 | - | 12.6 KB | -| Mighty | SingleFromQuery<dynamic> | dynamic | 130.59 μs | 2.432 μs | 3.677 μs | 2.0000 | 1.0000 | - | 12.43 KB | -| Dapper | 'Contrib Get<T>' | Post | 134.74 μs | 1.816 μs | 2.746 μs | 2.5000 | 1.0000 | 0.2500 | 12.29 KB | -| ServiceStack | SingleById<T> | Post | 135.01 μs | 1.213 μs | 2.320 μs | 3.0000 | 1.0000 | 0.2500 | 15.27 KB | -| LINQ to DB | First | Post | 151.87 μs | 3.826 μs | 5.784 μs | 3.0000 | 1.0000 | 0.2500 | 13.97 KB | -| EF 6 | SqlQuery | Post | 171.00 μs | 1.460 μs | 2.791 μs | 3.7500 | 1.0000 | - | 23.67 KB | -| DevExpress.XPO | GetObjectByKey<T> | Post | 172.36 μs | 3.758 μs | 5.681 μs | 5.5000 | 1.2500 | - | 29.06 KB | -| Dapper | 'Query<T> (unbuffered)' | Post | 174.40 μs | 3.296 μs | 4.983 μs | 2.0000 | 1.0000 | - | 11.77 KB | -| Dapper | 'Query<dynamic> (unbuffered)' | dynamic | 174.45 μs | 1.988 μs | 3.340 μs | 2.0000 | 1.0000 | - | 11.81 KB | -| DevExpress.XPO | FindObject<T> | Post | 181.76 μs | 5.554 μs | 9.333 μs | 8.0000 | - | - | 27.15 KB | -| DevExpress.XPO | Query<T> | Post | 189.81 μs | 4.187 μs | 8.004 μs | 10.0000 | - | - | 31.61 KB | -| EF Core | 'First (Compiled)' | Post | 199.72 μs | 3.983 μs | 7.616 μs | 4.5000 | - | - | 13.8 KB | -| NHibernate | Get<T> | Post | 248.71 μs | 6.604 μs | 11.098 μs | 5.0000 | 1.0000 | - | 29.79 KB | -| EF Core | First | Post | 253.20 μs | 3.033 μs | 5.097 μs | 5.5000 | - | - | 17.7 KB | -| NHibernate | HQL | Post | 258.70 μs | 11.716 μs | 17.712 μs | 5.0000 | 1.0000 | - | 32.1 KB | -| EF Core | SqlQuery | Post | 268.89 μs | 19.349 μs | 32.516 μs | 6.0000 | - | - | 18.5 KB | -| EF 6 | First | Post | 278.46 μs | 12.094 μs | 18.284 μs | 13.5000 | - | - | 44.18 KB | -| EF Core | 'First (No Tracking)' | Post | 280.88 μs | 8.192 μs | 13.765 μs | 3.0000 | 0.5000 | - | 19.38 KB | -| NHibernate | Criteria | Post | 304.90 μs | 2.232 μs | 4.267 μs | 11.0000 | 1.0000 | - | 60.29 KB | -| EF 6 | 'First (No Tracking)' | Post | 316.55 μs | 7.667 μs | 11.592 μs | 8.5000 | 1.0000 | - | 50.95 KB | -| NHibernate | SQL | Post | 335.41 μs | 3.111 μs | 4.703 μs | 19.0000 | 1.0000 | - | 78.86 KB | -| NHibernate | LINQ | Post | 807.79 μs | 27.207 μs | 45.719 μs | 8.0000 | 2.0000 | - | 53.65 KB | - +| ORM | Method | Return | Mean | StdDev | Error | Gen0 | Gen1 | Gen2 | Allocated | +|-------------------- |------------------------------- |------------- |----------:|----------:|----------:|--------:|-------:|-------:|----------:| +| Dapper cache impact | ExecuteParameters_Cache | Void | 96.75 us | 0.668 us | 1.010 us | 0.6250 | - | - | 2184 B | +| Dapper cache impact | QueryFirstParameters_Cache | Void | 96.86 us | 0.493 us | 0.746 us | 0.8750 | - | - | 2824 B | +| Hand Coded | SqlCommand | Post | 119.70 us | 0.706 us | 1.067 us | 1.3750 | 1.0000 | 0.1250 | 7584 B | +| Hand Coded | DataTable | dynamic | 126.64 us | 1.239 us | 1.873 us | 3.0000 | - | - | 9576 B | +| SqlMarshal | SqlCommand | Post | 132.36 us | 1.008 us | 1.523 us | 2.0000 | 1.0000 | 0.2500 | 11529 B | +| Dapper | QueryFirstOrDefault | Post | 133.73 us | 1.301 us | 2.186 us | 1.7500 | 1.5000 | - | 11608 B | +| Mighty | Query | dynamic | 133.92 us | 1.075 us | 1.806 us | 2.0000 | 1.7500 | - | 12710 B | +| LINQ to DB | Query | Post | 134.24 us | 1.068 us | 1.614 us | 1.7500 | 1.2500 | - | 10904 B | +| RepoDB | ExecuteQuery | Post | 135.83 us | 1.839 us | 3.091 us | 1.7500 | 1.5000 | - | 11649 B | +| Dapper | 'Query (buffered)' | Post | 136.14 us | 1.755 us | 2.653 us | 2.0000 | 1.5000 | - | 11888 B | +| Mighty | Query | Post | 137.96 us | 1.485 us | 2.244 us | 2.2500 | 1.2500 | - | 12201 B | +| Dapper | QueryFirstOrDefault | dynamic | 139.04 us | 1.507 us | 2.279 us | 3.5000 | - | - | 11648 B | +| Mighty | SingleFromQuery | dynamic | 139.74 us | 2.521 us | 3.811 us | 2.0000 | 1.7500 | - | 12710 B | +| Dapper | 'Query (buffered)' | dynamic | 140.13 us | 1.382 us | 2.090 us | 2.0000 | 1.5000 | - | 11968 B | +| ServiceStack | SingleById | Post | 140.76 us | 1.147 us | 2.192 us | 2.5000 | 1.2500 | 0.2500 | 15248 B | +| Dapper | 'Contrib Get' | Post | 141.09 us | 1.394 us | 2.108 us | 2.0000 | 1.5000 | - | 12440 B | +| Mighty | SingleFromQuery | Post | 141.17 us | 1.941 us | 2.935 us | 1.7500 | 1.5000 | - | 12201 B | +| Massive | 'Query (dynamic)' | dynamic | 142.01 us | 4.957 us | 7.494 us | 2.0000 | 1.5000 | - | 12342 B | +| LINQ to DB | 'First (Compiled)' | Post | 144.59 us | 1.295 us | 1.958 us | 1.7500 | 1.5000 | - | 12128 B | +| RepoDB | QueryField | Post | 148.31 us | 1.742 us | 2.633 us | 2.0000 | 1.5000 | 0.5000 | 13938 B | +| Norm | 'Read<> (tuples)' | ValueTuple`8 | 148.58 us | 2.172 us | 3.283 us | 2.0000 | 1.7500 | - | 12745 B | +| Norm | 'Read<()> (named tuples)' | ValueTuple`8 | 150.60 us | 0.658 us | 1.106 us | 2.2500 | 2.0000 | 1.2500 | 14562 B | +| RepoDB | Query | Post | 152.34 us | 2.164 us | 3.271 us | 2.2500 | 1.5000 | 0.2500 | 14106 B | +| RepoDB | QueryDynamic | Post | 154.15 us | 4.108 us | 6.210 us | 2.2500 | 1.7500 | 0.5000 | 13930 B | +| RepoDB | QueryWhere | Post | 155.90 us | 1.953 us | 3.282 us | 2.5000 | 0.5000 | - | 14858 B | +| Dapper cache impact | ExecuteNoParameters_NoCache | Void | 162.35 us | 1.584 us | 2.394 us | - | - | - | 760 B | +| Dapper cache impact | ExecuteNoParameters_Cache | Void | 162.42 us | 2.740 us | 4.142 us | - | - | - | 760 B | +| Dapper cache impact | QueryFirstNoParameters_Cache | Void | 164.35 us | 1.206 us | 1.824 us | 0.2500 | - | - | 1520 B | +| DevExpress.XPO | FindObject | Post | 165.87 us | 1.012 us | 1.934 us | 8.5000 | - | - | 28099 B | +| Dapper cache impact | QueryFirstNoParameters_NoCache | Void | 173.87 us | 1.178 us | 1.781 us | 0.5000 | - | - | 1576 B | +| LINQ to DB | First | Post | 175.21 us | 2.292 us | 3.851 us | 2.0000 | 0.5000 | - | 14041 B | +| EF 6 | SqlQuery | Post | 175.36 us | 2.259 us | 3.415 us | 4.0000 | 0.7500 | - | 24209 B | +| Norm | 'Read<> (class)' | Post | 186.37 us | 1.305 us | 2.496 us | 3.0000 | 0.5000 | - | 17579 B | +| DevExpress.XPO | GetObjectByKey | Post | 186.78 us | 3.407 us | 5.151 us | 4.5000 | 1.0000 | - | 30114 B | +| Dapper | 'Query (unbuffered)' | dynamic | 194.62 us | 1.335 us | 2.019 us | 1.7500 | 1.5000 | - | 12048 B | +| Dapper | 'Query (unbuffered)' | Post | 195.01 us | 0.888 us | 1.343 us | 2.0000 | 1.5000 | - | 12008 B | +| DevExpress.XPO | Query | Post | 199.46 us | 5.500 us | 9.243 us | 10.0000 | - | - | 32083 B | +| Belgrade | FirstOrDefault | Task`1 | 228.70 us | 2.181 us | 3.665 us | 4.5000 | 0.5000 | - | 20555 B | +| EF Core | 'First (Compiled)' | Post | 265.45 us | 17.745 us | 26.828 us | 2.0000 | - | - | 7521 B | +| NHibernate | Get | Post | 276.02 us | 8.029 us | 12.139 us | 6.5000 | 1.0000 | - | 29885 B | +| NHibernate | HQL | Post | 277.74 us | 13.032 us | 19.703 us | 8.0000 | 1.0000 | - | 31886 B | +| NHibernate | Criteria | Post | 300.22 us | 14.908 us | 28.504 us | 13.0000 | 1.0000 | - | 57562 B | +| EF 6 | First | Post | 310.55 us | 27.254 us | 45.799 us | 13.0000 | - | - | 43309 B | +| EF Core | First | Post | 317.12 us | 1.354 us | 2.046 us | 3.5000 | - | - | 11306 B | +| EF Core | SqlQuery | Post | 322.34 us | 23.990 us | 40.314 us | 5.0000 | - | - | 18195 B | +| NHibernate | SQL | Post | 325.54 us | 3.937 us | 7.527 us | 22.0000 | 1.0000 | - | 80007 B | +| EF 6 | 'First (No Tracking)' | Post | 331.14 us | 27.760 us | 46.649 us | 12.0000 | 1.0000 | - | 50237 B | +| EF Core | 'First (No Tracking)' | Post | 337.82 us | 27.814 us | 46.740 us | 3.0000 | 1.0000 | - | 17986 B | +| NHibernate | LINQ | Post | 604.74 us | 5.549 us | 10.610 us | 10.0000 | - | - | 46061 B | +| Dapper cache impact | ExecuteParameters_NoCache | Void | 623.42 us | 3.978 us | 6.684 us | 3.0000 | 2.0000 | - | 10001 B | +| Dapper cache impact | QueryFirstParameters_NoCache | Void | 630.77 us | 3.027 us | 4.576 us | 3.0000 | 2.0000 | - | 10640 B | Feel free to submit patches that include other ORMs - when running benchmarks, be sure to compile in Release and not attach a debugger (Ctrl+F5). @@ -444,7 +458,7 @@ Limitations and caveats --------------------- Dapper caches information about every query it runs, this allows it to materialize objects quickly and process parameters quickly. The current implementation caches this information in a `ConcurrentDictionary` object. Statements that are only used once are routinely flushed from this cache. Still, if you are generating SQL strings on the fly without using parameters it is possible you may hit memory issues. -Dapper's simplicity means that many feature that ORMs ship with are stripped out. It worries about the 95% scenario, and gives you the tools you need most of the time. It doesn't attempt to solve every problem. +Dapper's simplicity means that many features that ORMs ship with are stripped out. It worries about the 95% scenario, and gives you the tools you need most of the time. It doesn't attempt to solve every problem. Will Dapper work with my DB provider? --------------------- diff --git a/appveyor.yml b/appveyor.yml index 6197828f6..e766f8a28 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ skip_commits: - '**/*.md' install: - - choco install dotnet-sdk --version 7.0.402 + - choco install dotnet-sdk --version 8.0.100 environment: Appveyor: true diff --git a/benchmarks/Dapper.Tests.Performance/Benchmarks.PetaPoco.cs b/benchmarks/Dapper.Tests.Performance/Benchmarks.PetaPoco.cs index 1a3c99735..2af4f52b3 100644 --- a/benchmarks/Dapper.Tests.Performance/Benchmarks.PetaPoco.cs +++ b/benchmarks/Dapper.Tests.Performance/Benchmarks.PetaPoco.cs @@ -1,10 +1,32 @@ using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; using PetaPoco; using System.ComponentModel; using System.Linq; namespace Dapper.Tests.Performance { +#if !NET5_0_OR_GREATER +/* +System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. + ---> System.InvalidProgramException: Common Language Runtime detected an invalid program. + at System.Reflection.Emit.DynamicMethod.CreateDelegate(Type delegateType, Object target) + at PetaPoco.Database.PocoData.GetFactory[T](String key, Boolean ForceDateTimesToUtc, IDataReader r) in /_/benchmarks/Dapper.Tests.Performance/PetaPoco/PetaPoco.cs:line 1127 + at PetaPoco.Database.Fetch[T](String sql, Object[] args) in /_/benchmarks/Dapper.Tests.Performance/PetaPoco/PetaPoco.cs:line 458 + at Dapper.Tests.Performance.PetaPocoBenchmarks.FetchFast() in /_/benchmarks/Dapper.Tests.Performance/Benchmarks.PetaPoco.cs:line 38 + at BenchmarkDotNet.Autogenerated.Runnable_42.WorkloadActionUnroll(Int64 invokeCount) in /_/benchmarks/Dapper.Tests.Performance/bin/Release/net8.0/5e0d07b1-6b4c-4578-a0eb-d46563cab999/5e0d07b1-6b4c-4578-a0eb-d46563cab999.notcs:line 49834 + at BenchmarkDotNet.Engines.Engine.RunIteration(IterationData data) + at BenchmarkDotNet.Engines.EngineFactory.Jit(Engine engine, Int32 jitIndex, Int32 invokeCount, Int32 unrollFactor) + at BenchmarkDotNet.Engines.EngineFactory.CreateReadyToRun(EngineParameters engineParameters) + at BenchmarkDotNet.Autogenerated.Runnable_42.Run(IHost host, String benchmarkName) in /_/benchmarks/Dapper.Tests.Performance/bin/Release/net8.0/5e0d07b1-6b4c-4578-a0eb-d46563cab999/5e0d07b1-6b4c-4578-a0eb-d46563cab999.notcs:line 49238 + at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) + at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr) + --- End of inner exception stack trace --- + at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr) + at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) + at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) + at BenchmarkDotNet.Autogenerated.UniqueProgramName.AfterAssemblyLoadingAttached(String[] args) in /_/benchmarks/Dapper.Tests.Performance/bin/Release/net8.0/5e0d07b1-6b4c-4578-a0eb-d46563cab999/5e0d07b1-6b4c-4578-a0eb-d46563cab999.notcs:line 57 +*/ [Description("PetaPoco")] public class PetaPocoBenchmarks : BenchmarkBase { @@ -38,4 +60,5 @@ public Post FetchFast() return _dbFast.Fetch("SELECT * from Posts where Id=@0", i).First(); } } +#endif } diff --git a/benchmarks/Dapper.Tests.Performance/Benchmarks.RepoDB.cs b/benchmarks/Dapper.Tests.Performance/Benchmarks.RepoDB.cs index 6c16d60ce..10694ea79 100644 --- a/benchmarks/Dapper.Tests.Performance/Benchmarks.RepoDB.cs +++ b/benchmarks/Dapper.Tests.Performance/Benchmarks.RepoDB.cs @@ -2,6 +2,9 @@ using System.Linq; using BenchmarkDotNet.Attributes; using RepoDb; +using RepoDb.DbHelpers; +using RepoDb.DbSettings; +using RepoDb.StatementBuilders; namespace Dapper.Tests.Performance { @@ -13,6 +16,16 @@ public void Setup() { BaseSetup(); GlobalConfiguration.Setup().UseSqlServer(); + + // We need this since benchmarks using System.Data.SqlClient + var dbSetting = new SqlServerDbSetting(); + DbSettingMapper + .Add(dbSetting, true); + DbHelperMapper + .Add(new SqlServerDbHelper(), true); + StatementBuilderMapper + .Add(new SqlServerStatementBuilder(dbSetting), true); + ClassMapper.Add("Posts"); } diff --git a/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj b/benchmarks/Dapper.Tests.Performance/Dapper.Tests.Performance.csproj index 10ad41cff..52396c03e 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;net5.0 + net462;net8.0 false $(NoWarn);IDE0063;IDE0034;IDE0059;IDE0060 diff --git a/benchmarks/Dapper.Tests.Performance/DapperCacheImpact.cs b/benchmarks/Dapper.Tests.Performance/DapperCacheImpact.cs index 9e17249bf..5386a2833 100644 --- a/benchmarks/Dapper.Tests.Performance/DapperCacheImpact.cs +++ b/benchmarks/Dapper.Tests.Performance/DapperCacheImpact.cs @@ -10,7 +10,7 @@ public class DapperCacheImpact : BenchmarkBase [GlobalSetup] public void Setup() => BaseSetup(); - private object args = new { Id = 42, Name = "abc" }; + private readonly object args = new { Id = 42, Name = "abc" }; public class Foo { diff --git a/benchmarks/Dapper.Tests.Performance/LegacyTests.cs b/benchmarks/Dapper.Tests.Performance/LegacyTests.cs index ebd899dfb..dd9588b43 100644 --- a/benchmarks/Dapper.Tests.Performance/LegacyTests.cs +++ b/benchmarks/Dapper.Tests.Performance/LegacyTests.cs @@ -128,6 +128,7 @@ private static void Try(Action action, string blame) } } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1806:Do not ignore method results", Justification = "Intentional - just make sure we have something")] public async Task RunAsync(int iterations) { using (var connection = GetOpenConnection()) diff --git a/benchmarks/Dapper.Tests.Performance/app.config b/benchmarks/Dapper.Tests.Performance/app.config index 5ea174a5c..9e85395f8 100644 --- a/benchmarks/Dapper.Tests.Performance/app.config +++ b/benchmarks/Dapper.Tests.Performance/app.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 000000000..f3365c418 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "8.0.100" + } +} \ No newline at end of file diff --git a/tests/Dapper.Tests/Dapper.Tests.csproj b/tests/Dapper.Tests/Dapper.Tests.csproj index 8a003f7bd..5863bc8ed 100644 --- a/tests/Dapper.Tests/Dapper.Tests.csproj +++ b/tests/Dapper.Tests/Dapper.Tests.csproj @@ -2,9 +2,9 @@ Dapper.Tests Dapper Core Test Suite - net472;net6.0;net7.0 + net472;net6.0;net8.0 $(DefineConstants);MSSQLCLIENT - $(NoWarn);IDE0017;IDE0034;IDE0037;IDE0039;IDE0042;IDE0044;IDE0051;IDE0052;IDE0059;IDE0060;IDE0063;IDE1006;xUnit1004;CA1806;CA1816;CA1822;CA1825;CA2208 + $(NoWarn);IDE0017;IDE0034;IDE0037;IDE0039;IDE0042;IDE0044;IDE0051;IDE0052;IDE0059;IDE0060;IDE0063;IDE1006;xUnit1004;CA1806;CA1816;CA1822;CA1825;CA2208;CA1861 enable diff --git a/tests/Dapper.Tests/MiscTests.cs b/tests/Dapper.Tests/MiscTests.cs index aaaf8e978..cc762bf89 100644 --- a/tests/Dapper.Tests/MiscTests.cs +++ b/tests/Dapper.Tests/MiscTests.cs @@ -1310,5 +1310,16 @@ public HazGetOnlyAndCtor(int idProperty, string nameProperty) NameProperty = nameProperty; } } + + internal record struct One(int OID); + internal record struct Two(int OID, string Name); + + [Fact] + public async Task QuerySplitStruct() // https://github.com/DapperLib/Dapper/issues/2005 + { + var results = await connection.QueryAsync(@"SELECT 1 AS OID, 2 AS OID, 'Name' AS Name", (x,y) => (x,y), splitOn: "OID"); + + Assert.Single(results); + } } } diff --git a/tests/Dapper.Tests/Providers/FirebirdTests.cs b/tests/Dapper.Tests/Providers/FirebirdTests.cs index f63df6219..d234a8676 100644 --- a/tests/Dapper.Tests/Providers/FirebirdTests.cs +++ b/tests/Dapper.Tests/Providers/FirebirdTests.cs @@ -33,7 +33,7 @@ public void Issue178_Firebird() connection.Execute("insert into Issue178(id) values(42)"); // raw ADO.net using (var sqlCmd = new FbCommand(sql, connection)) - using (IDataReader reader1 = sqlCmd.ExecuteReader()) + using (var reader1 = sqlCmd.ExecuteReader()) { Assert.True(reader1.Read()); Assert.Equal(1, reader1.GetInt32(0)); diff --git a/tests/Dapper.Tests/Providers/PostgresqlTests.cs b/tests/Dapper.Tests/Providers/PostgresqlTests.cs index 32114370e..261490a53 100644 --- a/tests/Dapper.Tests/Providers/PostgresqlTests.cs +++ b/tests/Dapper.Tests/Providers/PostgresqlTests.cs @@ -49,7 +49,7 @@ public void TestPostgresqlArrayParameters() { using var conn = GetOpenNpgsqlConnection(); - IDbTransaction transaction = conn.BeginTransaction(); + var transaction = conn.BeginTransaction(); conn.Execute("create table tcat ( id serial not null, breed character varying(20) not null, name character varying (20) not null);"); conn.Execute("insert into tcat(breed, name) values(:Breed, :Name) ", Cats); @@ -66,7 +66,7 @@ public void TestPostgresqlListParameters() { using var conn = GetOpenNpgsqlConnection(); - IDbTransaction transaction = conn.BeginTransaction(); + var transaction = conn.BeginTransaction(); conn.Execute("create table tcat ( id serial not null, breed character varying(20) not null, name character varying (20) not null);"); conn.Execute("insert into tcat(breed, name) values(:Breed, :Name) ", new List(Cats));