diff --git a/Dapper/DbDecimal.cs b/Dapper/DbDecimal.cs
new file mode 100644
index 000000000..5679c6e26
--- /dev/null
+++ b/Dapper/DbDecimal.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Dapper
+{
+ ///
+ /// This class represents a SQL Decimal (Numeric) type, it can be used if you need
+ /// to be consistent with query parameter sizes, usually by specifying Precision and Scale
+ /// values that match the type in the database.
+ ///
+ public sealed class DbDecimal : SqlMapper.ICustomQueryParameter
+ {
+ private const byte _defaultPrecision = 38;
+ private const byte _defaultScale = 8;
+
+ ///
+ /// The value to be inserted or updated in the database
+ ///
+ public decimal Value { get; set; } = default;
+
+ ///
+ ///
+ ///
+ public byte Precision { get; set; } = _defaultPrecision;
+
+ ///
+ /// The number of decimal digits that are stored to the right of the
+ /// decimal point.
+ ///
+ public byte Scale { get; set; } = _defaultScale;
+
+ ///
+ /// The default constructor used when attaching the individual properties
+ /// of the parameter.
+ ///
+ public DbDecimal()
+ { }
+
+ ///
+ /// The primary constructor. This is the constructor that should generally
+ /// be used to create the object because it accepts values for the properties
+ /// used in the 90% use-case.
+ ///
+ /// The value to be inserted or updated in the database
+ /// The maximum total number of decimal digits to be stored.
+ /// The number of decimal digits that are stored to the right of the decimal point.
+ public DbDecimal(decimal value, byte precision, byte scale)
+ {
+ this.Value = value;
+ this.Precision = precision;
+ this.Scale = scale;
+ }
+
+ ///
+ /// Add the parameter to the command... internal use only
+ ///
+ ///
+ ///
+ public void AddParameter(IDbCommand command, string name)
+ {
+ bool add = !command.Parameters.Contains(name);
+
+ IDbDataParameter param;
+ if (add)
+ {
+ param = command.CreateParameter();
+ param.ParameterName = name;
+ }
+ else
+ {
+ param = (IDbDataParameter)command.Parameters[name];
+ }
+
+#pragma warning disable 0618
+ param.Value = SqlMapper.SanitizeParameterValue(Value);
+#pragma warning restore 0618
+ param.Precision = this.Precision;
+ param.Scale = this.Scale;
+ param.DbType = DbType.Decimal;
+
+ if (add)
+ {
+ command.Parameters.Add(param);
+ }
+ }
+
+ }
+}
diff --git a/tests/Dapper.Tests/MiscTests.cs b/tests/Dapper.Tests/MiscTests.cs
index 9323be671..99f13e9c6 100644
--- a/tests/Dapper.Tests/MiscTests.cs
+++ b/tests/Dapper.Tests/MiscTests.cs
@@ -1270,6 +1270,67 @@ public async void SO35470588_WrongValuePidValue()
Assert.Equal(568, row.Value);
}
+ [Fact]
+ public void TestDbDecimal()
+ {
+ var obj = connection.Query("select sql_variant_property(@a, 'precision') as a_precision, sql_variant_property(@a, 'scale') as a_scale, " +
+ "sql_variant_property(@b, 'precision') as b_precision, sql_variant_property(@b, 'scale') as b_scale, " +
+ "sql_variant_property(@c, 'precision') as c_precision, sql_variant_property(@c, 'scale') as c_scale, " +
+ "sql_variant_property(@d, 'precision') as d_precision, sql_variant_property(@d, 'scale') as d_scale, " +
+ "sql_variant_property(@e, 'precision') as e_precision, sql_variant_property(@e, 'scale') as e_scale",
+ new
+ {
+ a = new DbDecimal { Value = 123456.78M, Precision = 9, Scale = 3 },
+ b = new DbDecimal { Value = 123456.78M, Precision = 18, Scale = 3 },
+ c = new DbDecimal { Value = 123456.78M, Precision = 27, Scale = 3 },
+ d = new DbDecimal { Value = 123456.78M, Precision = 36, Scale = 3 },
+ e = new DbDecimal { Value = 123456.78M },
+ }).First();
+
+ Assert.Equal(3, (int)obj.a_scale);
+ Assert.Equal(9, (int)obj.a_precision);
+
+ Assert.Equal(3, (int)obj.b_scale);
+ Assert.Equal(18, (int)obj.b_precision);
+
+ Assert.Equal(3, (int)obj.c_scale);
+ Assert.Equal(27, (int)obj.c_precision);
+
+ Assert.Equal(3, (int)obj.d_scale);
+ Assert.Equal(36, (int)obj.d_precision);
+
+ Assert.Equal(8, (int)obj.e_scale);
+ Assert.Equal(38, (int)obj.e_precision);
+ }
+
+ [Fact]
+ public void TestDbDecimalUsingParameterizedConstructor()
+ {
+ var obj = connection.Query("select sql_variant_property(@a, 'precision') as a_precision, sql_variant_property(@a, 'scale') as a_scale, " +
+ "sql_variant_property(@b, 'precision') as b_precision, sql_variant_property(@b, 'scale') as b_scale, " +
+ "sql_variant_property(@c, 'precision') as c_precision, sql_variant_property(@c, 'scale') as c_scale, " +
+ "sql_variant_property(@d, 'precision') as d_precision, sql_variant_property(@d, 'scale') as d_scale",
+ new
+ {
+ a = new DbDecimal(123456.78M, 9, 3),
+ b = new DbDecimal(123456.78M, 18, 3),
+ c = new DbDecimal(123456.78M, 27, 3),
+ d = new DbDecimal(123456.78M, 36, 3),
+ }).First();
+
+ Assert.Equal(3, (int)obj.a_scale);
+ Assert.Equal(9, (int)obj.a_precision);
+
+ Assert.Equal(3, (int)obj.b_scale);
+ Assert.Equal(18, (int)obj.b_precision);
+
+ Assert.Equal(3, (int)obj.c_scale);
+ Assert.Equal(27, (int)obj.c_precision);
+
+ Assert.Equal(3, (int)obj.d_scale);
+ Assert.Equal(36, (int)obj.d_precision);
+ }
+
public class TPTable
{
public int Pid { get; set; }