diff --git a/Dapper.StrongName/Dapper.StrongName.csproj b/Dapper.StrongName/Dapper.StrongName.csproj
index 770b7ce7a..3d4ec4db0 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;net5.0;net7.0
+ net461;netstandard2.0;net6.0;net8.0
true
true
enable
diff --git a/Dapper/CommandDefinition.cs b/Dapper/CommandDefinition.cs
index 19963ba67..113d5239c 100644
--- a/Dapper/CommandDefinition.cs
+++ b/Dapper/CommandDefinition.cs
@@ -1,5 +1,6 @@
using System;
using System.Data;
+using System.Data.Common;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
@@ -113,6 +114,15 @@ private CommandDefinition(object? parameters, CommandFlags flags) : this()
CommandText = "";
}
+ internal CommandDefinition(IDbCommand cmd, CommandFlags flags = CommandFlags.None)
+ {
+ CommandText = cmd.CommandText;
+ CommandTypeDirect = cmd.CommandType;
+ CommandTimeout = cmd.CommandTimeout;
+ Transaction = cmd.Transaction;
+ Flags = flags;
+ }
+
///
/// For asynchronous operations, the cancellation-token
///
diff --git a/Dapper/Dapper.csproj b/Dapper/Dapper.csproj
index 28951f871..3a8ab454b 100644
--- a/Dapper/Dapper.csproj
+++ b/Dapper/Dapper.csproj
@@ -5,8 +5,9 @@
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;net5.0;net6.0;net7.0
+ net461;netstandard2.0;net6.0;net8.0;net9.0
enable
+ 13
true
diff --git a/Dapper/PublicAPI.Unshipped.txt b/Dapper/PublicAPI.Unshipped.txt
index 91b0e1a43..ab058de62 100644
--- a/Dapper/PublicAPI.Unshipped.txt
+++ b/Dapper/PublicAPI.Unshipped.txt
@@ -1 +1 @@
-#nullable enable
\ No newline at end of file
+#nullable enable
diff --git a/Dapper/PublicAPI/net5.0/PublicAPI.Unshipped.txt b/Dapper/PublicAPI/net5.0/PublicAPI.Unshipped.txt
deleted file mode 100644
index 91b0e1a43..000000000
--- a/Dapper/PublicAPI/net5.0/PublicAPI.Unshipped.txt
+++ /dev/null
@@ -1 +0,0 @@
-#nullable enable
\ No newline at end of file
diff --git a/Dapper/PublicAPI/net7.0/PublicAPI.Unshipped.txt b/Dapper/PublicAPI/net7.0/PublicAPI.Unshipped.txt
deleted file mode 100644
index 91b0e1a43..000000000
--- a/Dapper/PublicAPI/net7.0/PublicAPI.Unshipped.txt
+++ /dev/null
@@ -1 +0,0 @@
-#nullable enable
\ No newline at end of file
diff --git a/Dapper/PublicAPI/net5.0/PublicAPI.Shipped.txt b/Dapper/PublicAPI/net8.0/PublicAPI.Shipped.txt
similarity index 100%
rename from Dapper/PublicAPI/net5.0/PublicAPI.Shipped.txt
rename to Dapper/PublicAPI/net8.0/PublicAPI.Shipped.txt
diff --git a/Dapper/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/Dapper/PublicAPI/net8.0/PublicAPI.Unshipped.txt
new file mode 100644
index 000000000..5a5acf07e
--- /dev/null
+++ b/Dapper/PublicAPI/net8.0/PublicAPI.Unshipped.txt
@@ -0,0 +1,15 @@
+#nullable enable
+Dapper.SqlMapper.SqlBuilder
+Dapper.SqlMapper.SqlBuilder.AppendFormatted(bool value, string! format = "", string! expression = "") -> void
+Dapper.SqlMapper.SqlBuilder.AppendFormatted(T value, string! format = "", string! expression = "") -> void
+Dapper.SqlMapper.SqlBuilder.AppendLiteral(string! value) -> void
+Dapper.SqlMapper.SqlBuilder.Dispose() -> void
+Dapper.SqlMapper.SqlBuilder.GetCommandAndReset(System.Data.IDbTransaction? transaction, int? commandTimeout) -> System.Data.IDbCommand!
+Dapper.SqlMapper.SqlBuilder.SqlBuilder() -> void
+Dapper.SqlMapper.SqlBuilder.SqlBuilder(int literalLength, int formattedCount, System.Data.IDbConnection! connection) -> void
+static Dapper.SqlMapper.Execute(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> int
+static Dapper.SqlMapper.ExecuteScalar(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> object?
+static Dapper.SqlMapper.ExecuteScalar(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> T?
+static Dapper.SqlMapper.Query(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, bool buffered = false, int? commandTimeout = null) -> System.Collections.Generic.IEnumerable!
+static Dapper.SqlMapper.QueryBuffered(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> System.Collections.Generic.List!
+static Dapper.SqlMapper.QueryUnbuffered(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> System.Collections.Generic.IEnumerable!
\ No newline at end of file
diff --git a/Dapper/PublicAPI/net7.0/PublicAPI.Shipped.txt b/Dapper/PublicAPI/net9.0/PublicAPI.Shipped.txt
similarity index 100%
rename from Dapper/PublicAPI/net7.0/PublicAPI.Shipped.txt
rename to Dapper/PublicAPI/net9.0/PublicAPI.Shipped.txt
diff --git a/Dapper/PublicAPI/net9.0/PublicAPI.Unshipped.txt b/Dapper/PublicAPI/net9.0/PublicAPI.Unshipped.txt
new file mode 100644
index 000000000..256f267a6
--- /dev/null
+++ b/Dapper/PublicAPI/net9.0/PublicAPI.Unshipped.txt
@@ -0,0 +1,15 @@
+#nullable enable
+Dapper.SqlMapper.SqlBuilder
+Dapper.SqlMapper.SqlBuilder.AppendFormatted(bool value, string! format = "", string! expression = "") -> void
+Dapper.SqlMapper.SqlBuilder.AppendFormatted(T value, string! format = "", string! expression = "") -> void
+Dapper.SqlMapper.SqlBuilder.AppendLiteral(string! value) -> void
+Dapper.SqlMapper.SqlBuilder.Dispose() -> void
+Dapper.SqlMapper.SqlBuilder.GetCommandAndReset(System.Data.IDbTransaction? transaction, int? commandTimeout) -> System.Data.IDbCommand!
+Dapper.SqlMapper.SqlBuilder.SqlBuilder() -> void
+Dapper.SqlMapper.SqlBuilder.SqlBuilder(int literalLength, int formattedCount, System.Data.IDbConnection! connection) -> void
+static Dapper.SqlMapper.Execute(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> int
+static Dapper.SqlMapper.ExecuteScalar(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> object?
+static Dapper.SqlMapper.ExecuteScalar(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> T?
+static Dapper.SqlMapper.Query(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, bool buffered = false, int? commandTimeout = null) -> System.Collections.Generic.IEnumerable!
+static Dapper.SqlMapper.QueryBuffered(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> System.Collections.Generic.List!
+static Dapper.SqlMapper.QueryUnbuffered(this System.Data.IDbConnection! connection, ref Dapper.SqlMapper.SqlBuilder sql, System.Data.IDbTransaction? transaction = null, int? commandTimeout = null) -> System.Collections.Generic.IEnumerable!
diff --git a/Dapper/SqlMapper.Async.cs b/Dapper/SqlMapper.Async.cs
index 9408d5735..e166aed90 100644
--- a/Dapper/SqlMapper.Async.cs
+++ b/Dapper/SqlMapper.Async.cs
@@ -493,7 +493,7 @@ private static async Task QueryRowAsync(this IDbConnection cnn, Row row, T
T result = default!;
if (await reader.ReadAsync(cancel).ConfigureAwait(false) && reader.FieldCount != 0)
{
- result = ReadRow(info, identity, ref command, effectiveType, reader);
+ result = ReadRow(info, identity, in command, effectiveType, reader);
if ((row & Row.Single) != 0 && await reader.ReadAsync(cancel).ConfigureAwait(false)) ThrowMultipleRows(row);
while (await reader.ReadAsync(cancel).ConfigureAwait(false)) { /* ignore rows after the first */ }
@@ -1155,7 +1155,7 @@ public static Task ExecuteReaderAsync(this DbConnection cnn, Comma
private static async Task ExecuteWrappedReaderImplAsync(IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior)
{
- Action? paramReader = GetParameterReader(cnn, ref command);
+ Action? paramReader = GetParameterReader(cnn, in command);
DbCommand? cmd = null;
bool wasClosed = cnn.State == ConnectionState.Closed, disposeCommand = true;
diff --git a/Dapper/SqlMapper.SqlBuilder.cs b/Dapper/SqlMapper.SqlBuilder.cs
new file mode 100644
index 000000000..c39b1085e
--- /dev/null
+++ b/Dapper/SqlMapper.SqlBuilder.cs
@@ -0,0 +1,303 @@
+#if NET8_0_OR_GREATER
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text.RegularExpressions;
+
+namespace Dapper;
+
+public partial class SqlMapper
+{
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous")]
+ public static int Execute(
+ this IDbConnection connection,
+ [InterpolatedStringHandlerArgument("connection")] ref SqlBuilder sql,
+ IDbTransaction? transaction = null,
+ int? commandTimeout = null)
+ {
+ var cmd = sql.GetCommandAndReset(transaction, commandTimeout);
+ return ExecuteImpl(connection, new(cmd), cmd);
+ }
+
+#pragma warning disable CS1591, RS0016 // Missing XML comment for publicly visible type or member
+ public static int ExecuteNQ(
+#pragma warning restore CS1591, RS0016 // Missing XML comment for publicly visible type or member
+ this IDbConnection connection,
+ [InterpolatedStringHandlerArgument("connection")] ref SqlBuilder sql,
+ IDbTransaction? transaction = null,
+ int? commandTimeout = null) => Execute(connection, ref sql, transaction, commandTimeout);
+
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous")]
+ public static IEnumerable QueryUnbuffered(
+ this IDbConnection connection,
+ [InterpolatedStringHandlerArgument("connection")] ref SqlBuilder sql,
+ IDbTransaction? transaction = null,
+ int? commandTimeout = null)
+ {
+ var cmd = sql.GetCommandAndReset(transaction, commandTimeout);
+ return QueryImpl(connection, new(cmd), typeof(T), cmd);
+ }
+
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous")]
+ public static IEnumerable Query(
+ this IDbConnection connection,
+ [InterpolatedStringHandlerArgument("connection")] ref SqlBuilder sql,
+ IDbTransaction? transaction = null,
+ bool buffered = false,
+ int? commandTimeout = null)
+ {
+ var cmd = sql.GetCommandAndReset(transaction, commandTimeout);
+ var result = QueryImpl(connection, new(cmd, buffered ? CommandFlags.Buffered : CommandFlags.None), typeof(T), cmd);
+ return buffered ? result.ToList() : result;
+ }
+
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous")]
+ public static List QueryBuffered(
+ this IDbConnection connection,
+ [InterpolatedStringHandlerArgument("connection")] ref SqlBuilder sql,
+ IDbTransaction? transaction = null,
+ int? commandTimeout = null)
+ {
+ var cmd = sql.GetCommandAndReset(transaction, commandTimeout);
+ return QueryImpl(connection, new(cmd, CommandFlags.Buffered), typeof(T), cmd).ToList();
+ }
+
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("ApiDesign", "RS0026:Do not add multiple public overloads with optional parameters", Justification = "Not ambiguous")]
+ public static object? ExecuteScalar(
+ this IDbConnection connection,
+ [InterpolatedStringHandlerArgument("connection")] ref SqlBuilder sql,
+ IDbTransaction? transaction = null,
+ int? commandTimeout = null)
+ {
+ var cmd = sql.GetCommandAndReset(transaction, commandTimeout);
+ return ExecuteScalarImpl